Skip to content

Revise Python Notebook learning experience prototype - #3526

Draft
Andrew Casey (amcasey) wants to merge 102 commits into
mainfrom
amcasey/PythonLearning
Draft

Revise Python Notebook learning experience prototype#3526
Andrew Casey (amcasey) wants to merge 102 commits into
mainfrom
amcasey/PythonLearning

Conversation

@amcasey

Copy link
Copy Markdown
Member

Builds on #3394.

  • Removes a lot of the metadata files
  • Drops the learning panel for notebook courses
  • Adopts the Python Environments API
  • Explicitly creates a Python project for Jupyter to pick up as a kernel

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR revises the VS Code “QDK Learning” prototype to support multiple courses (including authored Python notebook courses), shifting the primary UX for notebook courses from the lesson panel to the notebook surface while adding per-course environment diagnostics and setup via the Python Environments API.

Changes:

  • Introduces a multi-course catalog + switching UX (tree view and webview branding/actions) and exposes course metadata via Copilot learning tools.
  • Adds support for python-notebook courses: drop-in course discovery (course.json + unit notebooks), workbook materialization, notebook sync, and exercise metadata parsing from cell tags.
  • Implements per-course Python environment management and diagnostics (extensions checks, venv setup, import checks).

Reviewed changes

Copilot reviewed 40 out of 43 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
source/vscode/test/suites/learning/test-workspace/qdk-learning/courses/circuit-diagrams-new/requirements.txt Adds pinned deps for a sample notebook course.
source/vscode/test/suites/learning/test-workspace/qdk-learning/courses/circuit-diagrams-new/README.md Course overview/requirements for the sample course.
source/vscode/test/suites/learning/test-workspace/qdk-learning/courses/circuit-diagrams-new/course.json Defines a drop-in course manifest and import checks.
source/vscode/test/suites/learning/test-workspace/qdk-learning/courses/circuit-diagrams-new/02-circuits/circuits.ipynb Adds authored unit notebook with exercises/hints/solutions.
source/vscode/test/suites/learning/test-workspace/qdk-learning/courses/circuit-diagrams-new/02-circuits/_unit.py Adds unit-specific Python exercise registration/checking.
source/vscode/test/suites/learning/test-workspace/qdk-learning/courses/circuit-diagrams-new/01-intro/intro.ipynb Adds intro unit notebook with first exercise.
source/vscode/test/suites/learning/test-workspace/qdk-learning/courses/circuit-diagrams-new/01-intro/_unit.py Adds intro unit exercise registration.
source/vscode/test/suites/learning/test-workspace/qdk-learning/courses/circuit-diagrams-new/_course_lib.py Adds shared notebook exercise harness utilities.
source/vscode/test/suites/learning/test-workspace/qdk-learning/courses/circuit-diagrams-new/_check_env.py Adds notebook-side environment check rendering.
source/vscode/test/suites/extensionUtils.ts Returns typed Extension API from activation helper.
source/vscode/test/runTests.mjs Adds the “learning” integration test suite option.
source/vscode/test/buildTests.mjs Adds build entrypoints for the learning test suite.
source/vscode/src/telemetry.ts Extends telemetry source enum with “notebook”.
source/vscode/src/learning/webview/webview.css Adds styling for course actions in the webview header.
source/vscode/src/learning/webview/webview-client.tsx Displays active course title and adds course info/browse actions.
source/vscode/src/learning/types.d.ts Adds multi-course, notebook exercise metadata, and env diagnostics types.
source/vscode/src/learning/service.ts Reworks service to handle multiple courses + notebook workflows + env checks.
source/vscode/src/learning/python/materialization.ts Materializes per-unit *.workbook.ipynb working copies.
source/vscode/src/learning/python/extensionUtils.ts Checks/prompts installation for Python + Jupyter extensions.
source/vscode/src/learning/python/environment.ts Adds per-course environment creation/import checks via Python Environments API.
source/vscode/src/learning/progressTreeView.ts Changes tree to Course → Unit → Activity, adds course nodes and Python contexts.
source/vscode/src/learning/panel.ts Disables panel for notebook courses; adds course switching/info commands from webview.
source/vscode/src/learning/notebookSync.ts Syncs service state/context keys with active course notebooks.
source/vscode/src/learning/notebookExercises.ts Parses exercises/hints/solutions from notebook cell tags; strips authoring cells.
source/vscode/src/learning/notebookCellStatusBar.ts Adds per-cell “Ask for a Hint” button for notebook exercises.
source/vscode/src/learning/katasProvider.ts Refactors katas loading into a provider; adds course metadata.
source/vscode/src/learning/index.ts Registers notebook sync/status bar provider; auto-completes exercises on execution.
source/vscode/src/learning/fsUtils.ts Adds shared FS helpers (exists / ensure parent dir).
source/vscode/src/learning/dropInCourseProvider.ts Discovers/parses drop-in notebook courses under qdk-learning/courses/*.
source/vscode/src/learning/courseProvider.ts Adds composite provider abstraction and course descriptors.
source/vscode/src/learning/courseLayout.ts Adds URIs for course roots/source notebooks/workbooks.
source/vscode/src/learning/constants.ts Adds constants for course folders, manifests, workbook suffix, notebook context key.
source/vscode/src/learning/commands.ts Adds course switching/info/diagnostics + notebook navigation helpers and reset-unit.
source/vscode/src/gh-copilot/tools.ts Exposes new learning tools (list/switch/info/check-environment).
source/vscode/src/gh-copilot/learningTools.ts Implements new chat tools and state serialization for courses/env checks.
source/vscode/package.json Wires new commands/menus for course nodes + notebook toolbar actions.
source/vscode/ai/qdk-learning.prompt.md Updates agent prompt to mention multiple courses.
source/vscode/ai/qdk-learning.agent.md Updates agent instructions to support multi-course + notebook courses.
source/vscode/.gitignore Ignores .vscode/ under extension folder.
package.json Adds @vscode/python-environments dependency.
package-lock.json Locks @vscode/python-environments and its engine constraints.
.vscode/launch.shared.json Updates debug launch to open the learning test workspace.
.gitignore Updates ignored learning workspace artifacts at repo root.

Comment on lines +99 to +105
// Register the course folder as a Python project. This creates a workspace
// setting, which causes Jupyter to pick up the venv.
const courseName = courseRoot.path.split("/").pop();
await api.addPythonProject({
name: `QDK Course: ${courseName}`,
uri: courseRoot,
});
Comment on lines +147 to +152
const results: { module: string; ok: boolean }[] = [];
for (const module of modules) {
const code = await runPython(api, env, ["-c", `import ${module}`]);
results.push({ module, ok: code === 0 });
}
return results;
Comment on lines +198 to +201
log.warn(
`Found multiple virtual environments, using first: ${envs.join(", ")}`,
);
return envs[0];
Comment on lines +97 to +102
errors.append(
"Install missing packages by running this in a new cell, then re-run this one:"
f"<pre> %pip install -r ../requirements.txt</pre>"
"Or click the <b>Run Course Diagnostics</b> button in the notebook toolbar "
"to set up the full environment."
)
Comment thread source/vscode/src/learning/service.ts Outdated
Comment on lines +1773 to +1776
// Expected when the file is missing or unparseable.
// In this case, leave ws (and, in particular, ws.ProgressData)
// untouched, since it's either the last known state or the default.
return;
* quick pick when invoked without one (e.g. from the command palette).
*/
async function resolveCourseId(
service: LearningService,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Take a note to review this carefully

* report, offering the fixes the report surfaces (e.g. one-click
* environment setup, install extensions).
*/
async function runEnvironmentCheckCommand(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Check this, there's supposed to be two buttons

},
() => service.runEnvironmentCheck(),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Check this part

return undefined;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

validation

this._onDidChangeCellStatusBarItems.event;

private readonly subscription: vscode.Disposable;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review

*
* VS Code activates this extension for any Jupyter notebook, so a session
* can be restored with a course workbook in the editor and the learning
* views never shown. Nothing else would initialize the service in that

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review

update(snapshot: OverallProgress | undefined): void {
this.snapshot = snapshot;
this.emitter.fire(undefined);
}

getTreeItem(node: LearningProgressNode): vscode.TreeItem {
if (node.kind === "course") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review

import {
checkPythonExtensions,
promptInstallPythonExtensions,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important review

@@ -344,7 +344,7 @@ type EventTypes = {
properties: {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

might make more changes to telemetry

"when": "false"
},
{
"command": "qsharp-vscode.learningNotebookExplain",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe a few commands and tools could be removed in case unnecessary

"quantum-katas"
],
"toolReferenceName": "qdkLearningCheckEnvironment",
"displayName": "QDK Learning: Check Environment",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Switch course review

* environment setup is available).
*/
async checkEnvironment(): Promise<EnvironmentCheckReport> {
// TODO (acasey): ensure only one can run at a time
const uri = this.getCurrentFileUri();
if (this.service.getActiveCourseInfo().kind === "python-notebook") {
return {
code: "", // TODO (acasey): can/should we get the code in the active cell?
// otherwise pick up where the learner left off.
if (service.getActiveCourseInfo().kind === "python-notebook") {
if (service.getProgress().stats.completedActivities === 0) {
// TODO (acasey): the readme serves as a sort of splash screen while things are set up.
service: LearningService,
node?: LearningProgressNode,
): Promise<void> {
// TODO (acasey): don't allow overlapping runs.
].join("\n");

const actions = report.fixes.map((r) => r.label);
// TODO (acasey): this dialog is ugly and unthemed - can we do better?
const course = this.requireCourse(ws, courseId);
// Idempotent: existing workbooks are left alone, so this only writes
// files the first time the learner opens the course.
// TODO (acasey): if materializing fails, you basically have to reload the
*/
private firstIncompletePosition(course: CatalogCourse): ActivityLocation {
for (const unit of course.units) {
// TODO (acasey): reuse firstIncompleteInUnit
throw err;
}
this.startWatcher();
// TODO (acasey): make sure we're firing this an appropriate number of times
if (activity.type === "exercise") {
// Python-notebook exercises live in the notebook — show their
// description as lesson text so the panel renders something useful.
// TODO (acasey): If we went back to using the lesson panel, we'd probably
this._onDidChangeState.fire(this.getState());

const units = this.requireWorkspace().catalog.units;
// TODO (acasey): do we actually want telemetry for other courses?
Comment thread package-lock.json
},
"node_modules/@vscode/python-environments": {
"version": "1.0.0",
"resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@vscode/python-environments/-/python-environments-1.0.0.tgz",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Make sure we don't merge with ms-feed-25

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.

5 participants