-
-
Notifications
You must be signed in to change notification settings - Fork 686
Fix fricas doctest pickling #40570
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
Fix fricas doctest pickling #40570
Conversation
Replace problematic doctest 'fricas == loads(dumps(fricas))' with 'isinstance(loads(dumps(a)), FriCAS)' where a is a fresh FriCAS instance. The original test was failing because the global 'fricas' object contains module-level lazy imports that cannot be pickled. Using a fresh instance and checking type instead of equality avoids the LazyImport pickling issue while still validating serialization round-trip functionality. Fixes doctest failures in sage.interfaces.fricas.FriCAS.__init__ and sage.interfaces.fricas.FriCAS._quit_string methods.
Fix ruff linting error W293 by removing trailing whitespace from blank line in doctest.
Remove malformed literal block structure in TESTS section that was causing RST218 error. Properly format the doctest examples.
Remove TESTS:: header that was causing RST218 literal block formatting error while preserving the meaningful doctest that verifies new process starts after quit(). This addresses linting compliance while maintaining documentation quality.
|
Documentation preview for this PR (built with commit e44838f; changes) is ready! 🎉 |
|
This test works for me (both from the command line and running |
@tscrim do you use system's fricas or sage's fricas?Thank you for your reply. |
@tscrim Thank you. I rebuild sage and fricas. But I found that I run |
|
Sorry for a delayed response. Does this mean you figured out the problem was local to your system? Otherwise why was this closed? |
I do not know how to solve it. Maybe It is just a problem with my system. So, I just closed it. Thank you for your reply. @tscrim |
|
@nbruin Then I reopen this. I think it is pickle a real object. |
|
I think the replacement test makes a lot of sense. You really want to test the pickling behaviour of fricas here; not that of a lazily imported object. |
wait… why do we care about picklability of the interface object anyway? I feel if the intention is to test that (but whatever, it isn't doing any harm) another note.
does these other systems have the same issue? (evidently yes. Except that they don't have load/dump test. Then why having one here?) that test has been there since the very beginning. Might as well be historical accident (or that it actually work before). #34547 adds this part (thus break the test, probably). |
|
I don't know where to find it these days, but we used to have a coverage report that would complain about untested methods. This was usually a very good thing but in corner cases it would encourage you to write a dumb test for something that didn't really need its own test. |
there's still the coverage-report workflow running. The status report as GitHub annotation appears to stop working some time ago for some reason (possibly some major overhaul like the meson migration or the CI refactor), and nobody actually looked. looking at one of the recent pull request e.g. #41082 you can still click through https://github.com/sagemath/sage/actions/runs/18637280279/job/53131673368?pr=41082#step:13:314 and reach https://app.codecov.io/github/sagemath/sage/commit/f29eb1ade0cd78d4d125699c40f603496fbdfc18 . I'm not entirely sure how to read that, but looks like the information is there. for comparison, the GitHub annotation used to look like this. https://github.com/sagemath/sage/pull/38259/files#diff-2c12e62924e49ca61ef92a008aa860551fa8a4c6ad841061eab030b24d28b1e4R869 |
|
It looks like that coverage test is actually keeping track of which lines get executed (and hence can find untested branches in the code. It used to be more primitive: just keeping track of whether each function ended up being called during testing. A test like I don't know how it would work for an interface object: make sure that the "global" interface object is just looked up and returned? The serialization in this case would probably come into play for message-passing parallel things, where an object must be serialized and sent to another process. That's always going to be fairly fragile with objects in an interface (although sage does try to have those relatively state-free). In any case, when |
|
Note that any lazily imported object should be resolved and replaced by the first call. So the change in the test should be fully equivalent to the current test. Any such failure is a bug in the testing framework with lazily imported objects. |
Is it part of the lint check? It was nice to have that… At least we can call it manually by
Those “dumb” tests can be much more useful than you are giving them credit for. Also, there should be absolutely no exception to the 100% doctest (for new/modified functions) coverage rules. |
That was the attempted fix on #41054 . It's tricky, though. When you ask The fix in #41054 was lowered in priority mainly due to the observation that https://peps.python.org/pep-0810/ would perhaps get native lazy imports into python. We'd eventually migrate to that. It's also strange to pickle lazy imports: if it's worth pickling, why wasn't it loaded already? It seems to me almost always an indication of something fishy if code ends up trying to pickle a lazy import object. |
There is no way to determine if it is a lazy import. If we do something like
Indeed, it would be great if that got in. Although it would have to wait 5-10 years after it incorporated (assuming it does) in order to not force people to upgrade their Python to such a current version...
This might happen when doing a computation in parallel, where communication is done via pickling. For an interface, it shouldn't be shared, but it might be passing some lazily imported algebraic object (e.g., I don't experience any issues with the test as written though. However, we could just explicitly resolve the import in a line beforehand as a hackaround... |
Not true (and in fact there are things that can happen with objects without a method being called on them. And there are some methods that are present on lazy_import objects that get fetched without going through |
as far as I can tell, (https://stackoverflow.com/questions/56879245/) That said, make |
sagemathgh-40570: Fix fricas doctest pickling <!-- ^ Please provide a concise and informative title. --> <!-- ^ Don't put issue numbers in the title, do this in the PR description below. --> <!-- ^ For example, instead of "Fixes sagemath#12345" use "Introduce new method to calculate 1 + 2". --> <!-- v Describe your changes below in detail. --> <!-- v Why is this change required? What problem does it solve? --> <!-- v If this PR resolves an open issue, please link to it here. For example, "Fixes sagemath#12345". --> Fix FriCAS doctest pickling failures Problem: Doctests in sage.interfaces.fricas were failing with TypeError: cannot pickle 'sage.misc.lazy_import.LazyImport' object when testing ```fricas == loads(dumps(fricas))```. ``` sage: fricas == loads(dumps(fricas)) ------------------------------------------------------------------------ --- TypeError Traceback (most recent call last) File ~/sage/src/sage/misc/persist.pyx:338, in sage.misc.persist.dumps() 337 type_obj = type((<LazyImport>obj).get_object()) --> 338 ans = type_obj.dumps(obj, compress) 339 except (AttributeError, RuntimeError, TypeError): File ~/sage/src/sage/structure/sage_object.pyx:508, in sage.structure.sage_object.SageObject.dumps() 507 --> 508 return _base_dumps(self, compress=compress) 509 File ~/sage/src/sage/misc/persist.pyx:306, in sage.misc.persist._base_dumps() 305 global already_pickled --> 306 gherkin = SagePickler.dumps(obj) 307 already_pickled = {} File ~/sage/src/sage/misc/persist.pyx:830, in sage.misc.persist.SagePickler.dumps() 829 pickler = cls(buf, **kwargs) --> 830 pickler.dump(obj) 831 already_pickled = {} TypeError: cannot pickle 'sage.misc.lazy_import.LazyImport' object During handling of the above exception, another exception occurred: TypeError Traceback (most recent call last) Cell In[1], line 1 ----> 1 fricas == loads(dumps(fricas)) File ~/sage/src/sage/misc/persist.pyx:340, in sage.misc.persist.dumps() 338 ans = type_obj.dumps(obj, compress) 339 except (AttributeError, RuntimeError, TypeError): --> 340 ans = _base_dumps(obj, compress=compress) 341 already_pickled = {} 342 return ans File ~/sage/src/sage/misc/persist.pyx:306, in sage.misc.persist._base_dumps() 304 305 global already_pickled --> 306 gherkin = SagePickler.dumps(obj) 307 already_pickled = {} 308 File ~/sage/src/sage/misc/persist.pyx:830, in sage.misc.persist.SagePickler.dumps() 828 buf = io.BytesIO() 829 pickler = cls(buf, **kwargs) --> 830 pickler.dump(obj) 831 already_pickled = {} 832 return buf.getvalue() TypeError: cannot pickle 'sage.misc.lazy_import.LazyImport' object ``` Solution: Replace the problematic equality test with isinstance(loads(dumps(a)), FriCAS) using a fresh FriCAS instance instead of the global fricas object, which contains unpicklable lazy imports. Changes: Modified doctests in ```FriCAS.__init__ ``` and ```FriCAS._quit_string``` methods Preserves serialization testing while avoiding LazyImport pickling issues ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - sagemath#12345: short description why this is a dependency --> <!-- - sagemath#34567: ... --> URL: sagemath#40570 Reported by: Chenxin Zhong Reviewer(s):
Fix FriCAS doctest pickling failures
Problem: Doctests in sage.interfaces.fricas were failing with TypeError: cannot pickle 'sage.misc.lazy_import.LazyImport' object when testing
fricas == loads(dumps(fricas)).Solution: Replace the problematic equality test with isinstance(loads(dumps(a)), FriCAS) using a fresh FriCAS instance instead of the global fricas object, which contains unpicklable lazy imports.
Changes:
Modified doctests in
FriCAS.__init__andFriCAS._quit_stringmethodsPreserves serialization testing while avoiding LazyImport pickling issues
📝 Checklist
⌛ Dependencies