diff --git a/extensions/positron-python/src/client/positron/webAppContexts.ts b/extensions/positron-python/src/client/positron/webAppContexts.ts index 77d0d4a15ae..4a6afe10e9b 100644 --- a/extensions/positron-python/src/client/positron/webAppContexts.ts +++ b/extensions/positron-python/src/client/positron/webAppContexts.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import { executeCommand } from '../common/vscodeApis/commandApis'; const libraries: string[] = ['streamlit', 'shiny', 'gradio', 'flask', 'fastapi']; export function detectWebApp(document: vscode.TextDocument): void { const text = document.getText(); const foundImports = importsInApp(text); - vscode.commands.executeCommand('setContext', 'pythonFileContainsApp', foundImports); - console.log('set context pythonFileContainsApp', foundImports); + executeCommand('setContext', 'pythonFileContainsApp', foundImports); } // find import statements for specified libraries via import XXXX or from XXX import @@ -24,9 +24,9 @@ function importsInApp(text: string): boolean { export function getAppFramework(text: string): string | undefined { const importPattern = new RegExp(`import\\s+(${libraries.join('|')})`, 'g'); - const fromImportPattern = new RegExp(`from\\s+(${libraries.join('|')})\\S*import`, 'g'); - + const fromImportPattern = new RegExp(`from\\s+(${libraries.join('|')})\\S*\\simport`, 'g'); const importMatch = importPattern.exec(text); + if (importMatch) { return importMatch[1]; } diff --git a/extensions/positron-python/src/client/terminals/codeExecution/codeExecutionManager.ts b/extensions/positron-python/src/client/terminals/codeExecution/codeExecutionManager.ts index 2bc3a6cd342..9690ebeccc0 100644 --- a/extensions/positron-python/src/client/terminals/codeExecution/codeExecutionManager.ts +++ b/extensions/positron-python/src/client/terminals/codeExecution/codeExecutionManager.ts @@ -30,7 +30,6 @@ import { //import { getAppFramework } from '../../positron/webAppContexts' // --- End Positron --- - @injectable() export class CodeExecutionManager implements ICodeExecutionManager { private eventEmitter: EventEmitter = new EventEmitter(); @@ -41,7 +40,7 @@ export class CodeExecutionManager implements ICodeExecutionManager { @inject(IFileSystem) private fileSystem: IFileSystem, @inject(IConfigurationService) private readonly configSettings: IConfigurationService, @inject(IServiceContainer) private serviceContainer: IServiceContainer, - ) { } + ) {} public get onExecutedCode(): Event { return this.eventEmitter.event; diff --git a/extensions/positron-python/src/test/positron/webAppContexts.unit.test.ts b/extensions/positron-python/src/test/positron/webAppContexts.unit.test.ts new file mode 100644 index 00000000000..49ff293e6fa --- /dev/null +++ b/extensions/positron-python/src/test/positron/webAppContexts.unit.test.ts @@ -0,0 +1,58 @@ +import * as vscode from 'vscode'; +import * as sinon from 'sinon'; +import { assert } from 'chai'; +import * as cmdApis from '../../client/common/vscodeApis/commandApis'; +import { detectWebApp, getAppFramework } from '../../client/positron/webAppContexts'; +import { IDisposableRegistry } from '../../client/common/types'; + +suite('Discover webapp frameworks', () => { + let document: vscode.TextDocument; + let executeCommandStub: sinon.SinonStub; + const disposables: IDisposableRegistry = []; + + setup(() => { + executeCommandStub = sinon.stub(cmdApis, 'executeCommand'); + document = { + getText: () => '', + } as vscode.TextDocument; + }); + + teardown(() => { + sinon.restore(); + disposables.forEach((d) => d.dispose()); + }); + + const texts = ['import streamlit', 'from shiny.ui import page_navbar', 'import numpy']; + texts.forEach((text) => { + const expected = !text.includes('numpy'); + test('should set context pythonFileContainsApp if application is found', () => { + document.getText = () => text; + detectWebApp(document); + + assert.ok(executeCommandStub.calledOnceWith('setContext', 'pythonFileContainsApp', expected)); + }); + }); + + const frameworks = ['streamlit', 'shiny', 'gradio', 'flask', 'fastapi', 'numpy']; + frameworks.forEach((framework) => { + const expected = framework === 'numpy' ? undefined : framework; + test(`should detect ${expected}: import framework`, () => { + const text = `import ${framework}`; + const actual = getAppFramework(text); + + assert.strictEqual(actual, expected); + }); + test(`should detect ${expected}: from framework.test import XYZ`, () => { + const text = `from ${framework}.test import XYZ`; + const actual = getAppFramework(text); + + assert.strictEqual(actual, expected); + }); + test(`should detect ${expected}: from framework import XYZ`, () => { + const text = `from ${framework} import XYZ`; + const actual = getAppFramework(text); + + assert.strictEqual(actual, expected); + }); + }); +}); diff --git a/extensions/positron-python/src/test/terminals/codeExecution/codeExecutionManager.unit.test.ts b/extensions/positron-python/src/test/terminals/codeExecution/codeExecutionManager.unit.test.ts index 55eb51d1c31..5854c5c5e52 100644 --- a/extensions/positron-python/src/test/terminals/codeExecution/codeExecutionManager.unit.test.ts +++ b/extensions/positron-python/src/test/terminals/codeExecution/codeExecutionManager.unit.test.ts @@ -90,6 +90,7 @@ suite('Terminal - Code Execution Manager', () => { [ // --- Start Positron --- // Add the Positron execute in console command and execute selection in console command. + Commands.Exec_App_In_Terminal, Commands.Exec_In_Console, Commands.Exec_Selection_In_Console, // --- End Positron ---