Skip to content

Conversation

DavidKutu
Copy link

@DavidKutu DavidKutu commented Jun 18, 2021

For #6207
For #6215
For #6376

  • Pull request represents a single change (i.e. not fixing disparate/unrelated things in a single PR).
  • Title summarizes what is changing.
  • Has a news entry file (remember to thank yourself!).
  • Appropriate comments and documentation strings in the code.
  • Has sufficient logging.
  • Has telemetry for enhancements.
  • Unit tests & system/integration tests are added/updated.
  • Test plan is updated as appropriate.
  • package-lock.json has been regenerated by running npm install (if dependencies have changed).

@codecov-commenter
Copy link

codecov-commenter commented Jun 18, 2021

Codecov Report

Merging #6332 (e76e780) into main (b45c387) will decrease coverage by 0%.
The diff coverage is 30%.

❗ Current head e76e780 differs from pull request most recent head be54e0c. Consider uploading reports for the commit be54e0c to get more accurate results

@@          Coverage Diff           @@
##            main   #6332    +/-   ##
======================================
- Coverage     69%     69%    -1%     
======================================
  Files        407     410     +3     
  Lines      27918   28253   +335     
  Branches    4138    4186    +48     
======================================
+ Hits       19487   19598   +111     
- Misses      6774    6989   +215     
- Partials    1657    1666     +9     
Impacted Files Coverage Δ
src/client/common/installer/productInstaller.ts 41% <0%> (-7%) ⬇️
src/client/common/types.ts 100% <ø> (ø)
src/client/datascience/baseJupyterSession.ts 70% <0%> (-2%) ⬇️
...science/jupyter/kernels/kernelDependencyService.ts 79% <0%> (-10%) ⬇️
src/client/debugger/jupyter/kernelDebugAdapter.ts 5% <5%> (ø)
src/client/debugger/jupyter/debuggingManager.ts 36% <36%> (ø)
...client/datascience/commands/activeEditorContext.ts 88% <68%> (-4%) ⬇️
src/client/common/utils/localize.ts 95% <100%> (+<1%) ⬆️
src/client/datascience/constants.ts 99% <100%> (+<1%) ⬆️
...lient/datascience/jupyter/kernels/cellExecution.ts 70% <100%> (+<1%) ⬆️
... and 12 more

@DavidKutu DavidKutu changed the title David/debuging Debugging (run by line) spike Jun 18, 2021
David added 8 commits June 18, 2021 15:58
- start the kernel when starting a debug session
(if its not started already)
-toggle the breapoint margin automatically
- handle the case when we attach and the kernel is stopped
and dump them all when the debug session starts
import { ICell, IDebuggingCellMap, INotebookExecutionLogger } from '../../datascience/types';

@injectable()
export class DebuggingCellMap implements IDebuggingCellMap, INotebookExecutionLogger {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a draft here, but this class could use some class comments about what it's responsible for.

@@ -272,6 +273,7 @@ export const INotebookExecutionLogger = Symbol('INotebookExecutionLogger');
export interface INotebookExecutionLogger extends IDisposable {
preExecute(cell: ICell, silent: boolean): Promise<void>;
postExecute(cell: ICell, silent: boolean, language: string, resource: Uri): Promise<void>;
nativePostExecute(cell: NotebookCell): Promise<void>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this an optional method, this way you don't need to modify all other classes.

Suggested change
nativePostExecute(cell: NotebookCell): Promise<void>;
nativePostExecute?(cell: NotebookCell): Promise<void>;

@@ -63,6 +63,12 @@ export abstract class BaseJupyterSession implements IJupyterSession {
}
return this.onStatusChangedEvent.event;
}
public get onIOPubMessageSignal(): Event<KernelMessage.IIOPubMessage> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to remove the "Signal" from the name here, it's only a Signal down in the Juypter code doesn't really make sense to have that on the name here.

) {}

public async activate() {
vscode.debug.breakpoints; // start to fetch breakpoints
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the API this looks like a non-async array, why are the results just ignored here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems really weird to do on extension activation? Fetch breakpoints?

@DavidKutu DavidKutu marked this pull request as ready for review June 24, 2021 23:11
@DavidKutu DavidKutu requested a review from a team as a code owner June 24, 2021 23:11
.get<IPythonExecutionFactory>(IPythonExecutionFactory)
.createActivatedEnvironment({ resource: uri, interpreter, allowEnvironmentFetchExceptions: true });

const output = pythonProcess.execObservable(['-m', 'pip', 'show', executableName], {});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work for conda? Meaning will running pip show give you the correct information in a conda environment?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use -m ipython --version or the existing api as mentioned by ian

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the reason:
image

I think the python api uses the bottom command, and it gives the version of something different (its ipython) and that wouldn't work. I'll check their code, but for this PR we might want to do it ourselves.

And fix it for Conda of course.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a python expert (could consider asking the python folks). But an easier way if we can't use the python -m version check or python api then might be to activate the environment and do like this:

python -c "import ipykernel; print(ipykernel.version)"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try it, although it would be nice to not have to activate it

interpreter: PythonEnvironment,
_token?: CancellationToken
): Promise<boolean> {
return this.installer.getVersion(Product.ipykernel, interpreter).then((version) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would async/await be more readable here? You forgot a 'catch' clause I think. Might be easier with try, await getVersion, parse versoin, catch - return false

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanup commit
although, I will check if we can accomplish this with the python api.

There's the issue that python -m ipykernel --version returns the ipython version instead of the ipykernel version. Hopefully the python api deals with that.

}
}),

vscode.commands.registerCommand('jupyter.debugNotebook', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have commands in a 'commands.ts' file? So that this string is one spot.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanup commit

await this.debugInfo();
}

// after disconnecting, hide the breakpoint margin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate a bit in this comment? I assume detaching is the same as hitting the 'debug' button on the toolbar. Can the user also cause this by just hitting the stop button during debugging?

Seems weird to me. Stopping during debugging should just interrrupt the cell I think.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normally nothing needs to happen here. But since vscode has a command that shows and hides the breakpoint margin for notebooks, we need to hide it at some point. And the best time to do it is on the disconnect command.

Comment on lines 150 to 156
const cell = this.fileToCell.get(source.path);
if (cell) {
source.name = path.basename(cell.document.uri.path);
if (cell.index >= 0) {
source.name += `, Cell ${cell.index + 1}`;
}
source.path = cell.document.uri.toString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is common with the code above? Meaning can you make a separate function or lambda?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanup commit

const cell = this.notebookDocument.getCells().find((c) => c.document.uri.toString() === uri);
if (cell) {
try {
const response = await this.session.customRequest('dumpCell', { code: cell.document.getText() });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this means the kernel has to support this request. I guess it's okay cause ipykernel is probably the only reasonable case for debugging, but maybe we should flag this somehow so we don't forget it when we try getting debugging working elsewhere.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by flagging? With a comment?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah with a comment here and maybe an issue? ipykernel supports 'dumpcell' but does xeus?

move the debug context to its own function
@@ -126,6 +126,54 @@ export abstract class BaseInstaller {
.install(product, resource, cancel, reInstallAndUpdate);
}

public async getVersion(product: Product, resource?: InterpreterUri): Promise<string | undefined> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did using the pythonAPI function not work here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the reason:
image

I think the python api uses the bottom command, and it gives the version of something different (its ipython) and that wouldn't work. I'll check their code, but for this PR we might want to do it ourselves.

And fix it for Conda of course.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For modules (which ipykernel should be treated as), I believe the Python API uses

python -c 'import ipykernel; print(ipykernel.__version__)'

which would yield the right result

image

https://github.com/microsoft/vscode-python/blob/362eb34cafcbc513919eb4d78ea0521a0ed6738a/src/client/common/process/internal/python.ts#L104-L112

@@ -173,6 +180,31 @@ export class ActiveEditorContextService implements IExtensionSingleActivationSer
}
this.updateContextOfActiveNotebookKernel(activeEditor);
}
private async updateDebugContext(activeEditor?: INotebookEditor, interpreter?: PythonEnvironment) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the second parameter case (interpreter) coming from? The only usage of this looks to just be passed an editor.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That one used to come from kernel status change, but that didn't work right. I need to create an event for kernel change.


private getDebuggerByUri(document: vscode.NotebookDocument): Debugger | undefined {
for (const [doc, dbg] of this.notebookToDebugger.entries()) {
if (document.uri.toString() === doc.uri.toString()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per-discussion here: #6358 (comment) I believe we can just compare on documents.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanup commit

version: '5.2',
msg_type: 'debug_request',
username: 'vscode',
session: randomBytes(8).toString('hex')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might work for the spike, but for JMP messages session should be unique per session. It's not random per message. You can get the id of an existing session off the ISession on the IJupyterSession.


this.sendMessage.fire(msg.content);
};
control.onStdin = (msg) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does anything actually come in on stdin?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, nothing, I'll remove it

package.json Outdated
"debuggers": [
{
"type": "kernel",
"label": "Kernel Debug"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

II think this should be called Jupyter Python or Python Kernel or similar, as it's specific to python not just any kernel.
This will matter in full debugging, user needs to select the right debug config (based on the label)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to Python Kernel on the cleanup commit

/**
* Dump content of given cell into a tmp file and return path to file.
*/
private async dumpCell(uri: string): Promise<void> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who has ownership of the file here? Looks like ipykernel returns back a sourcePath for the file created in a success message. But I'm not seeing cleanup on the ipykernel side.

const response = await this.session.customRequest('debugInfo');

// If there's breakpoints at this point, delete them
if (response.breakpoints.lenght > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks misspelled, "length." Sorry in a PR I can't see the type easily is it an any? Not sure why this would build.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanup commit
I created types for these responses to avoid that

command: 'setBreakpoints',
arguments: {
source: {
path: response.breakpoints[0].source
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will they all have the same source here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanup commit
Small change, but instead of deleting the breakpoints on the kernel, I instead sent a message to VS Code to register them.

@DavidKutu
Copy link
Author

DavidKutu commented Jun 25, 2021

To do

  • Add context for switching kernels and notebook opened
  • cache valid kernels so the button enables faster
  • don't make up a random session ids
  • delete temp files (the kernel is not doing this)
  • use python api for checking ipykernel version
  • use IDisposableRegistry
  • check if we need the vscode.debug.breakpoints on activate

if (activeEditor) {
this.notebookProvider
.getOrCreateNotebook({ identity: activeEditor.file, resource: activeEditor.file, getOnly: true })
.then(async (nb) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just an await here instead of chaining stuff?

const cell = this.notebookDocument.getCells().find((c) => c.document.uri.toString() === uri);
if (cell) {
try {
const response = await this.session.customRequest('dumpCell', { code: cell.document.getText() });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah with a comment here and maybe an issue? ipykernel supports 'dumpcell' but does xeus?

@DavidKutu
Copy link
Author

@rchiodo for your second comment, I added this at the top of the file

// For info on the custom requests implemented by jupyter see:

I put it there because the whole debug adapter need support for those 2 special messages.

-pr comment on chaining stuff vs await
@DavidKutu DavidKutu merged commit ce2739a into main Jun 28, 2021
@DavidKutu DavidKutu deleted the david/debuging branch June 28, 2021 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants