@@ -270,6 +270,120 @@ def create_vscode_settings():
270270 return True
271271
272272
273+ def validate_kernel_setup ():
274+ """
275+ Validate that the APIM Samples kernel is properly registered and accessible.
276+
277+ Returns:
278+ bool: True if kernel is properly configured, False otherwise
279+ """
280+
281+ try :
282+ # Check if ipykernel is available
283+ result = subprocess .run ([sys .executable , '-m' , 'jupyter' , 'kernelspec' , 'list' ],
284+ check = True , capture_output = True , text = True )
285+
286+ # Check if our kernel is in the list
287+ if 'apim-samples' in result .stdout :
288+ print ("✅ APIM Samples kernel found in kernelspec list" )
289+ return True
290+ else :
291+ print ("❌ APIM Samples kernel not found in kernelspec list" )
292+ return False
293+
294+ except subprocess .CalledProcessError as e :
295+ print (f"❌ Failed to check kernel list: { e } " )
296+ return False
297+ except FileNotFoundError :
298+ print ("❌ Jupyter not found - please ensure Jupyter is installed" )
299+ return False
300+
301+
302+ def force_kernel_consistency ():
303+ """
304+ Enforce kernel consistency by removing conflicting kernels and ensuring
305+ only the APIM Samples kernel is used for notebooks.
306+ """
307+
308+ print ("🔧 Enforcing kernel consistency..." )
309+
310+ # First, ensure our kernel is registered
311+ if not validate_kernel_setup ():
312+ print ("⚠️ Kernel not found, attempting to register..." )
313+ if not install_jupyter_kernel ():
314+ print ("❌ Failed to register kernel - manual intervention required" )
315+ return False
316+
317+ # Update VS Code settings with strict kernel enforcement
318+ project_root = get_project_root ()
319+ vscode_dir = project_root / '.vscode'
320+ settings_file = vscode_dir / 'settings.json'
321+
322+ # Enhanced kernel settings that prevent VS Code from changing kernels
323+ strict_kernel_settings = {
324+ "jupyter.defaultKernel" : "apim-samples" ,
325+ "jupyter.kernels.changeKernelIdForNotebookEnabled" : False ,
326+ "jupyter.kernels.filter" : [
327+ {
328+ "path" : "apim-samples" ,
329+ "type" : "pythonEnvironment"
330+ }
331+ ],
332+ "jupyter.preferredKernelIdForNotebook" : {
333+ "*.ipynb" : "apim-samples"
334+ },
335+ "jupyter.kernels.trusted" : [
336+ "./.venv/Scripts/python.exe" if os .name == 'nt' else "./.venv/bin/python"
337+ ],
338+ # Prevent VS Code from auto-detecting other Python environments
339+ "jupyter.kernels.excludePythonEnvironments" : [
340+ "**/anaconda3/**" ,
341+ "**/conda/**" ,
342+ "**/miniconda3/**" ,
343+ "**/python3.*" ,
344+ "*/site-packages/*" ,
345+ "/bin/python" ,
346+ "/bin/python3" ,
347+ "/opt/python/*/bin/python*" ,
348+ "/usr/bin/python" ,
349+ "/usr/bin/python3" ,
350+ "/usr/local/bin/python" ,
351+ "/usr/local/bin/python3" ,
352+ "python" ,
353+ "python3" ,
354+ "**/.venv/**/python*" ,
355+ "**/Scripts/python*" ,
356+ "**/bin/python*"
357+ ]
358+ }
359+
360+ try :
361+ import json
362+
363+ # Read existing settings or create new ones
364+ existing_settings = {}
365+ if settings_file .exists ():
366+ try :
367+ with open (settings_file , 'r' , encoding = 'utf-8' ) as f :
368+ existing_settings = json .load (f )
369+ except json .JSONDecodeError :
370+ print ("⚠️ Existing settings.json has issues, creating new one" )
371+
372+ # Merge settings, with our strict kernel settings taking priority
373+ existing_settings .update (strict_kernel_settings )
374+
375+ # Write updated settings
376+ with open (settings_file , 'w' , encoding = 'utf-8' ) as f :
377+ json .dump (existing_settings , f , indent = 4 )
378+
379+ print ("✅ Strict kernel enforcement settings applied" )
380+ return True
381+
382+ except Exception as e :
383+ print (f"❌ Failed to update VS Code settings: { e } " )
384+ return False
385+
386+
273387def setup_complete_environment ():
274388 """
275389 Complete setup: generate .env file, register kernel, and configure VS Code.
@@ -288,25 +402,32 @@ def setup_complete_environment():
288402 print ("2. Registering standardized Jupyter kernel..." )
289403 kernel_success = install_jupyter_kernel ()
290404
291- # Step 3: Configure VS Code settings
405+ # Step 3: Configure VS Code settings with strict kernel enforcement
292406 print ("\n 3. Configuring VS Code workspace settings..." )
293407 vscode_success = create_vscode_settings ()
294408
409+ # Step 4: Enforce kernel consistency
410+ print ("\n 4. Enforcing kernel consistency for future reliability..." )
411+ consistency_success = force_kernel_consistency ()
412+
295413 # Summary
296414 print ("\n " + "=" * 50 )
297415 print ("📋 Setup Summary:" )
298416 print (f" ✅ Python path configuration: Complete" )
299417 print (f" { '✅' if kernel_success else '❌' } Jupyter kernel registration: { 'Complete' if kernel_success else 'Failed' } " )
300418 print (f" { '✅' if vscode_success else '❌' } VS Code settings: { 'Complete' if vscode_success else 'Failed' } " )
419+ print (f" { '✅' if consistency_success else '❌' } Kernel consistency enforcement: { 'Complete' if consistency_success else 'Failed' } " )
301420
302- if kernel_success and vscode_success :
421+ if kernel_success and vscode_success and consistency_success :
303422 print ("\n 🎉 Setup complete! Your local environment now matches the dev container experience." )
304423 print (" • Notebooks will automatically use the 'APIM Samples Python 3.12' kernel" )
305424 print (" • Python modules from shared/ directory are available" )
306425 print (" • VS Code is configured for optimal workflow" )
426+ print (" • Kernel selection is locked to prevent auto-changes" )
307427 print ("\n 💡 Next steps:" )
308428 print (" 1. Restart VS Code to apply all settings" )
309429 print (" 2. Open any notebook - it should automatically use the correct kernel" )
430+ print (" 3. The kernel should remain consistent across all notebooks" )
310431 else :
311432 print ("\n ⚠️ Setup completed with some issues. Check error messages above." )
312433
@@ -394,6 +515,9 @@ def show_help():
394515 elif command == "--setup-vscode" :
395516 # Just configure VS Code settings
396517 create_vscode_settings ()
518+ elif command == "--force-kernel" :
519+ # Force kernel consistency and prevent changes
520+ force_kernel_consistency ()
397521 elif command == "--complete-setup" :
398522 # Full setup: everything needed for local development
399523 setup_complete_environment ()
0 commit comments