Closed rhkarls closed 5 months ago
Hey @rhkarls, thanks for reporting. I think this is a problem with IPython 8.15, so could you downgrade to 8.14 and try again?
@impact27, could you take a look at this one? I was able to reproduce point 2) above and it only affects master.
Hey @rhkarls, thanks for reporting. I think this is a problem with IPython 8.15, so could you downgrade to 8.14 and try again?
Indeed, downgrading to 8.14 works for spyder_env.
However, for the custom env downgrading to 8.14 does not work.
In the case of 1) above: same CommsErrorWrapper as in the initial report. In the case of 2) above: now this also causes the CommsErrorWrapper, not TypeError as in the initial report with 8.15.
The "TypeError: unsupported operand type(s) for +: 'int' and 'str'" should be fixed by https://github.com/spyder-ide/spyder-kernels/pull/467 so point 2) should not happen in master?
for point 1) https://github.com/spyder-ide/spyder-kernels/pull/476 will send the correct error which is maybe a cloud pickle issue
@rhkarls, Spyder alpha3 will be released in a couple of days, so let us know if this error persists with that version.
Thanks! And I want to add that the debugging plugin is such an amazing improvement for Spyder, great stuff!
With 6a3 it works as expected with python 3.10 using both Spyder interpreter and custom interpreter. Testing with 3.11 and 3.12 in the custom environment it does however not work as expected, as the debugging does not properly enter the interactive debugger or show the stack in the debugger plugin.
How it works with 3.10 custom env:
And using 3.12 in custom env (same for 3.11):
Exception shown in the gif:
Exception in comms call get_current_frames:
File "C:\Users\user\AppData\Local\mambaforge\envs\spyder-6a3\lib\site-packages\spyder_kernels\comms\commbase.py", line 298, in _comm_message
buffer = cloudpickle.loads(msg['buffers'][0])
AttributeError: 'FrameSummary' object has no attribute 'end_lineno'
In case it helps: as far as I can see this error remains on 6.0.0a5 and spyder-kernels 3.0.0b5 if Spyder is installed in an env with python 3.10.
When Spyder 6.0.0a5 is installed with Python 3.11 the examples above work as expected with Spyders own environment and with custom environments with python 3.10, 3.11 and 3.12.
Could you try with https://github.com/spyder-ide/spyder-kernels/pull/492 ?
@impact27, I was able to reproduce this. And after applying your patch in #492, now I'm seeing this error:
Exception in comms call get_current_frames:
File "/home/carlos/Projects/spyder/spyder/external-deps/spyder-kernels/spyder_kernels/comms/commbase.py", line 298, in _comm_message
buffer = cloudpickle.loads(msg['buffers'][0])
AttributeError: Can't get attribute '_class_setstate' on <module 'cloudpickle.cloudpickle' from '/home/carlos/miniconda3/envs/py310-pip/lib/python3.10/site-packages/cloudpickle/cloudpickle.py'>
This happens after clicking in the Interrupt execution button because the debugger also hangs in this case.
That is not an helpful error :/ is this only an issue when you cross python versions correct? @ccordoba12 what versions os python did you use?
That is not an helpful error :/
Sorry, that's what I'm seeing but I can get more info if you need it.
is this only an issue when you cross python versions correct?
Yep, I confirmed it is.
@ccordoba12 what versions os python did you use?
Python 3.10 in the frontend (i.e. for Spyder) and 3.12 for the kernel.
Sorry, that's what I'm seeing but I can get more info if you need it.
I assume _class_setstate
indeed exists (https://github.com/cloudpipe/cloudpickle/blob/f111f7ab6d302e9b1e2a568d0e4c574895db6a6e/cloudpickle/cloudpickle.py#L1150) and that the AttributeError
was raised in this method. Can you easily debug and check what the arguments are? (obj, state, attrname, attr)
After making the cloudpickle
versions match, I got this error:
Exception in comms call get_current_frames:
File "/home/carlos/Projects/spyder/spyder/external-deps/spyder-kernels/spyder_kernels/comms/commbase.py", line 298, in _comm_message
buffer = cloudpickle.loads(msg['buffers'][0])
TypeError: code expected at most 16 arguments, got 18
which a quick googling pointed to this issue: https://github.com/cloudpipe/cloudpickle/issues/451.
And this https://github.com/cloudpipe/cloudpickle/issues/451#issuecomment-1501050455 on that issue mentions that, according to Cloudpickle's Readme
Cloudpickle can only be used to send objects between the exact same version of Python.
which is still present in it.
But after taking a closer look at Cloudpickle's code, I found the _code_reduce
function (thanks to https://github.com/cloudpipe/cloudpickle/pull/467):
If I understand it correctly, it means that:
I tested the second case and it's working as expected (without the changes in PR #492). I'll test the first one next week, unless @rhkarls beats me to it.
Cloudpickle can only be used to send objects between the exact same version of Python.
That is not ideal. I guess the problem is that if named tuple is not the same between versions of python then you can't do anything?
I tried to change the definition of SpyderFrameSummary to a custom frame but this will be a problem more generally.
Most comms send and receive basic objects (strings, list, dict, float) but some are more general and this will be a problem. (get/set_value for example)
@ccordoba12 with a few adjustments we can replace cloudpickle with json so this class of problem disappears
Ok, I saw your PRs about it. But I'd like to know how get/set_value is going to work without Cloudpickle because I think we need it to serialize arbitrary Python objects. And I doubt serializing them with json is enough for all objects.
Is it not possible to send the frame info back to Spyder using a dict to avoid doing removing Cloudpickle?
The problem here is that cloudpickle only works for the exact same version of python, and we use in general different versions of python, and therefore can not use cloudpickle. I tried replacing cloudpickle with json and all the tests are passing. In general if this is a problem we just need to encode in the calling function whatever object we want to send between the kernel and frontend. But I think we need to be careful about doing that. The current solution hides this complexity and introduces hard to detect and debug bugs. Do you know of any example where this might be a problem?
What we could do is to use cloudpickle only in get/set_value?
The problem here is that cloudpickle only works for the exact same version of python, and we use in general different versions of python, and therefore can not use cloudpickle.
Sure, I understand that. But we haven't had any serious issues so far (as far as I recall this is the first one).
I tried replacing cloudpickle with json and all the tests are passing.
Yeah, but we're testing simple objects (Numpy arrays and dataframes) which (I guess) are easily serializable with json.
In general if this is a problem we just need to encode in the calling function whatever object we want to send between the kernel and frontend. But I think we need to be careful about doing that. The current solution hides this complexity and introduces hard to detect and debug bugs.
Ok, that seems quite reasonable.
Do you know of any example where this might be a problem?
No, but I doubt our users wouldn't take long to find problems with this new approach because they're using it to view all kind of objects.
However, I wouldn't like to discard what you've done but complement it, if possible, by sending objects with Cloudpickle and Jsonpickle to be able to display objects created with libraries not available on the Spyder side. That would be a significant improvement for users of our installers because it's not easy to install other libraries on them.
I guess most users are using the same interpreter for the kernel and frontend, so the issue with cloudpickle doesn’t show up that much.
If the only use for cloudpickle is the variable explorer, then it should be used only there. This will greatly simplify the handling of errors. We could for example serialise with cloudpickle and then send the base64 representation by comms so there is no need to have more complexity in the comms
the more general question I have because I am not that much knowledgeable with the variable explorer is: how do we edit a generic python object? Don’t we need a specific editor for each class?
If the only use for cloudpickle is the variable explorer, then it should be used only there. This will greatly simplify the handling of errors. We could for example serialise with cloudpickle and then send the base64 representation by comms so there is no need to have more complexity in the comms
I tried that in https://github.com/spyder-ide/spyder/pull/22120
the more general question I have because I am not that much knowledgeable with the variable explorer is: how do we edit a generic python object? Don’t we need a specific editor for each class?
We have one editor called ObjectExplorer (IIRC) which works on arbitrary objects, but it can only be used to view objects, not to edit them. We have separate editors for list/set/tuple, numpy arrays and pandas dataframe.
Actually, the use of cloudpickle in the variable explorer is also problematic,
However, I wouldn't like to discard what you've done but complement it, if possible, by sending objects with Cloudpickle and Jsonpickle to be able to display objects created with libraries not available on the Spyder side. That would be a significant improvement for users of our installers because it's not easy to install other libraries on them.
I don't understand this. How can we unpickle an object if its class is not installed on the Spyder side?
I don't understand this. How can we unpickle an object if its class is not installed on the Spyder side?
from cloud pickle doc:
Among other things, cloudpickle supports pickling for lambda functions along with functions and classes defined interactively in the __main__ module (for instance in a script, a shell or a Jupyter notebook).
One advantage of my approach in the PR is that it makes it easy to find a new solution for this in the future. Indeed cloud pickle is only used in get/set_value so another solution can easily be deployed without affecting the rest of the comms.
I don't understand this. How can we unpickle an object if its class is not installed on the Spyder side?
By using Jsonpickle, which creates a Json representation of a Python object that we can display in a Json tree viewer. So, the object wouldn't be editable but at least users would be able to check its internals.
By using Jsonpickle, which creates a Json representation of a Python object that we can display in a Json tree viewer. So, the object wouldn't be editable but at least users would be able to check its internals.
Got it, we don't unpickle but read the json directly. That sounds like a good approach.
I think this is a spyder-kernels issue, apologies if not!
Using Spyder 6 alpha 2 and spyder-kernels 3.0.0b2, with a simple .py file with one line
1/0
. Spyder is installed using mamba following the instructions on https://github.com/spyder-ide/spyder/releasesTwo different ways to attempt debugging 1) Debug file (CTRL+F5) 2) Run file, then use
%debug
magic in consoleWith two different environments,
spyder-env
where Spyder is installed (3.10) andcustom_env
running Python 3.11.For 1) Spyder crashes with
TypeError: 'CommsErrorWrapper' object is not subscriptable
using the custom conda environment (custom_env
). It does not crash when using the same environment as Spyder (spyder-env
).For 2), running the file, then %debug in ipython console raises TypeError below both with custom environment and using the
spyder-env
where Spyder 6a2 is installed.Versions
Dependencies