-
Notifications
You must be signed in to change notification settings - Fork 65
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
Pre-proposal: Kernel messages to get and set variables #115
Comments
Friendly ping to some schemas experts 😉 @bollwyvl @tonyfast @agoose77 @JohanMabille cc @afshin (as this originates from our discussions). |
I'll confess I haven't fully dug into the details of the proposed schema, but do think there is a fair amount of benefit in considering reuse of an existing wire format messages, such as those provided by LSP. While LSP and DAP are document-based instead of namespace-based, there's already a great deal of work (and value) represented in them, and duplicating these features (except "Jupyter-flavored") seems to be heading back to the bikeshed, as there's already setVariable and friends. Perhaps the heavy "i am debugging" modal switch can be relaxed in some way so that these messages would work in a more general, albeit reduced, way. Tying these together with LSP: this would likely include As to how these actually get called: as an alternative to novel named messages, one approach might be for an active kernel to advertise a jupyter comm target for, e.g. This is different than the approach demonstrated in the horribly-bitrotten LSP proxy kernel PR, which uses comm, but mostly benefited from moving multiple language servers' connections to a single, well-understood websocket (which is itself an interactive kernel, which is fun), but shows the general pattern. |
+1 on the ability to inspect and modify the variables, this is definitely a mandatory feature. Here are some thoughts on this:
I think the variable explorer and the variable inspector form the debugger (when the debugger is supported by the kernel) should be the same visual entity to avoid confusion. However, that means that the variable explorer / variable inspector would show the local variables only when the debugger is active and the execution has stopped on a breakpoint.
Actually the DAP offers the setVariable request, which allows to edit or create variables, but only in a suspendend state (i.e. breakpoint or pause). However we could extend this mechanism to suppor the feature in all the cases, just like we did with the I agree with @bollwyvl that we should leverage on already existing messages. The DAP seems more adapted than the LSP to me (although I'm biased since I'm more educated to the DAP than the LSP), but it has some constraint: DAP messages must be sent over the control channel in order to work when the code is suspended (this is also true for "extended DAP" messages such as inpectVariables). Also the kernel already advertises the features it supports through the kernel_info_request/kernel_info_reply messages, I don't think we need to duplicate this mechanism with an additional jupyter comm target. A mean to avoid specification (and code) duplication could be to:
|
Thanks both for your comments. One point I still don't get how to achieve is the ability to handle partial get/set. I see that the DAP request as something to do pagination. But it looks like, it is pagination for the children of a container (like attributes of a class). But for Jupyter we need to go a step further and support array/dataframe pagination. And I don't see how the current DAP request address this exactly. According to the DAP, a Variable can have the following attributes to support pagination: /**
* The number of named child variables.
* The client can use this information to present the children in a paged UI
* and fetch them in chunks.
*/
namedVariables?: number;
/**
* The number of indexed child variables.
* The client can use this information to present the children in a paged UI
* and fetch them in chunks.
*/
indexedVariables?: number; Does that means we should paginate nd-array and dataframe as flatten array? And for interface SetVariableArguments {
/**
* The reference of the variable container. The `variablesReference` must have
* been obtained in the current suspended state. See 'Lifetime of Object
* References' in the Overview section for details.
*/
variablesReference: number;
/**
* The name of the variable in the container.
*/
name: string;
/**
* The value of the variable.
*/
value: string;
/**
* Specifies details on how to format the response value.
*/
format?: ValueFormat;
} What would be a good solution? extend that request? |
Actually, each element of an array is a variable, so it is possible to directly use pagination for arrays; for partial assignment of arrays, the new setVariables / editVariables request could support additional attributes; when receiving such a request, the kernel could simply dispatch Regarding dataframes / nd arrays, the variable request would indeed expose their internal structures. I don't have a good answer for this, maybe an additional request for getting a way to paginate a variable depending on its type, but that would be really more involved. Or we could do something similar to what VIsual Studio does, let the possibility to write custom visualizers as Jupyter extensions (and Jupyter Lab would provide default fallbacks only for nd arrays / dataframes). |
I understand the value in building on top of already-existing protocols, but if kernels have to implement the DAP or LSP protocols in order to support this feature, I'm afraid we are going to leave a lot of kernels behind. v[3] # single element
v[1:5] # range of elements
v[7:1:-2] # step
v[1:7, 4:8] # two dimensions We could even support attribute access, either through the dot ( v.path.to.attribute[3]
v["path"]["to"]["attribute"][3] |
Kernels would not have to implement the full DAP to support the get/set variable feature:
This works for simple variable types such as integers or string, where the value is easy to write in a message. What if you want to assign an array of complex objects? The current specification in the DAP with nested variable references is very flexible, although a bit more complicated to implement than the syntax you describe. Also reusing the Variable type means that we would have the same mechanism for the following use cases:
Otherwise, we have two mechanisms to implement (since the DAP already enforces its own). |
Correct me if I'm wrong, but we will always get/set variables as representations, right? Typically, we will get Python's |
Not only, for a structured variable, you also get a variable reference that you can use in a new get request to get the nested variables; also the representation of a structured variable is usually quite short. For the set request, you can evaluate a complex value expression and assign it to a lvalue expression; for instance, a SetExpressionArguments used in a SetExpressionRequest could be: {
"expression": "v[i]",
"value": "new ComplicatedObject(a, 3)"
} Therefore the values of the fields are language dependent, while the specification of the fields is language agnostic. |
This is exactly what I want to avoid with this proposal. get and set should be language agnostic so that client don't need to know the language. If the value is to be expressed in the kernel language, I don't see a value for a new JEP as basically we can do this with silence request to the kernel as done in extension such as variable inspector. We could do something similar to the kernel reply using some mimetypes and a data buffer. If the specification restrain the mimetype to something like a |
The goal would be to transfer serialized version of a variable (not necessary string although However that approach does not seem to fit well with the existing |
I feel like this:
suggests to me that the get reply should be (or include) a mimebundle representation, so it's consistent with the rest of the ways objects are represented in Jupyter, and Jupyter frontends can display variables with the tools already available to them. This would allow extensions like variable inspector to move to a more official/stable API without needing to reimplement representations for DAP Variable outputs. We could add a specific mime-type (application/json+dap-variable or something) and recommend it's populated (or require it, but that seems unnecessary to me). |
Summary
Add two kernel messages to get and set variables fully or partially (e.g. slice of a data frame).
Motivation
We should aim at user experience close to MatLab/Spyder rather than an IDE regarding user / kernel variables interaction; aka high flexibility to introspect and modify variable values on the fly.
Looking for example at the Spyder variable explorer, we can see it is easy to edit simple variables, add new ones (from scratch or by duplication).
Requirements
[Draft] Implementation details
This feature will be flagged as optional building on top of provisional JEP 92.
New kernel message
get_variables
:Notes:
if no variable are specified, the kernel must return all available variables.
pagination is optional
New kernel message
set_variables
:Rationale and alternatives
We could expand on the debugger adapter protocol. But the debugger feature has the following disadvantages:
We could use silent
execute
request:Prior art
Variable explorers are an important features in science exploratory softwares; here are some examples
Extensions for existing Jupyter UI:
Unresolved questions
How should this feature interact with the debugger?
How to express variable type and its serialization over the wire?
How to specify array and data frame slicing?
Should we support slicing for more data types?
Future possibilities
A nice side effect of these new messages will be the ability to introduce no-code/low-code cells like Colab forms, SQL cells (the result of the cell would be a set message to the kernel),... . It could also help in developing polyglot kernels.
Edited:
type
inmimetype
The text was updated successfully, but these errors were encountered: