diff --git a/.travis.yml b/.travis.yml index fee4079ea762..915c33dd9cad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,8 +36,8 @@ before_install: | yarn global add azure-cli export TRAVIS_PYTHON_PATH=`which python` install: - - pip install --upgrade -r requirements.txt - - pip install -t ./pythonFiles/experimental/ptvsd git+https://github.com/Microsoft/ptvsd/ + - python -m pip install --upgrade -r requirements.txt + - python -m pip install -t ./pythonFiles/experimental/ptvsd git+https://github.com/Microsoft/ptvsd/ - yarn script: diff --git a/.vscode/settings.json b/.vscode/settings.json index be66f967c5c4..7ce29c7c0813 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,8 @@ "files.exclude": { "out": true, // set this to true to hide the "out" folder with the compiled JS files "**/*.pyc": true, + "obj": true, + "bin": true, "**/__pycache__": true, "node_modules": true, ".vscode-test": true, @@ -19,4 +21,4 @@ "python.unitTest.promptToConfigure": false, "python.workspaceSymbols.enabled": false, "python.formatting.provider": "none" -} \ No newline at end of file +} diff --git a/news/3 Code Health/1318.md b/news/3 Code Health/1318.md new file mode 100644 index 000000000000..d0f965f5a448 --- /dev/null +++ b/news/3 Code Health/1318.md @@ -0,0 +1 @@ +Ensure all unit tests run on Travis use the right Python interpreter. diff --git a/requirements.txt b/requirements.txt index e7f764089ecf..439a8d6999b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,3 +10,5 @@ pytest fabric numba rope +flask +django diff --git a/src/client/terminals/codeExecution/djangoShellCodeExecution.ts b/src/client/terminals/codeExecution/djangoShellCodeExecution.ts index 5fbe2ef2d19f..4fc230b6e21a 100644 --- a/src/client/terminals/codeExecution/djangoShellCodeExecution.ts +++ b/src/client/terminals/codeExecution/djangoShellCodeExecution.ts @@ -10,14 +10,13 @@ import { ICommandManager, IDocumentManager, IWorkspaceService } from '../../comm import '../../common/extensions'; import { IFileSystem, IPlatformService } from '../../common/platform/types'; import { ITerminalServiceFactory } from '../../common/terminal/types'; -import { IConfigurationService } from '../../common/types'; -import { IDisposableRegistry } from '../../common/types'; +import { IConfigurationService, IDisposableRegistry } from '../../common/types'; import { DjangoContextInitializer } from './djangoContext'; import { TerminalCodeExecutionProvider } from './terminalCodeExecution'; @injectable() export class DjangoShellCodeExecutionProvider extends TerminalCodeExecutionProvider { - constructor( @inject(ITerminalServiceFactory) terminalServiceFactory: ITerminalServiceFactory, + constructor(@inject(ITerminalServiceFactory) terminalServiceFactory: ITerminalServiceFactory, @inject(IConfigurationService) configurationService: IConfigurationService, @inject(IWorkspaceService) workspace: IWorkspaceService, @inject(IDocumentManager) documentManager: IDocumentManager, @@ -30,10 +29,10 @@ export class DjangoShellCodeExecutionProvider extends TerminalCodeExecutionProvi this.terminalTitle = 'Django Shell'; disposableRegistry.push(new DjangoContextInitializer(documentManager, workspace, fileSystem, commandManager)); } - public getReplCommandArgs(resource?: Uri): { command: string, args: string[] } { + public getReplCommandArgs(resource?: Uri): { command: string; args: string[] } { const pythonSettings = this.configurationService.getSettings(resource); const command = this.platformService.isWindows ? pythonSettings.pythonPath.replace(/\\/g, '/') : pythonSettings.pythonPath; - const args = pythonSettings.terminal.launchArgs.slice(); + const args = pythonSettings.terminal!.launchArgs.slice(); const workspaceUri = resource ? this.workspace.getWorkspaceFolder(resource) : undefined; const defaultWorkspace = Array.isArray(this.workspace.workspaceFolders) && this.workspace.workspaceFolders.length > 0 ? this.workspace.workspaceFolders[0].uri.fsPath : ''; diff --git a/src/test/common.ts b/src/test/common.ts index e399012adf2c..5f6d6640e709 100644 --- a/src/test/common.ts +++ b/src/test/common.ts @@ -7,6 +7,8 @@ import { IS_MULTI_ROOT_TEST } from './initialize'; const fileInNonRootWorkspace = path.join(__dirname, '..', '..', 'src', 'test', 'pythonFiles', 'dummy.py'); export const rootWorkspaceUri = getWorkspaceRoot(); +export const PYTHON_PATH = getPythonPath(); + export type PythonSettingKeys = 'workspaceSymbols.enabled' | 'pythonPath' | 'linting.lintOnSave' | 'linting.enabled' | 'linting.pylintEnabled' | @@ -118,3 +120,12 @@ const globalPythonPathSetting = workspace.getConfiguration('python').inspect('py export const clearPythonPathInWorkspaceFolder = async (resource: string | Uri) => retryAsync(setPythonPathInWorkspace)(resource, ConfigurationTarget.WorkspaceFolder); export const setPythonPathInWorkspaceRoot = async (pythonPath: string) => retryAsync(setPythonPathInWorkspace)(undefined, ConfigurationTarget.Workspace, pythonPath); export const resetGlobalPythonPathSetting = async () => retryAsync(restoreGlobalPythonPathSetting)(); + +function getPythonPath(): string { + // tslint:disable-next-line:no-unsafe-any + if (process.env.TRAVIS_PYTHON_PATH && fs.existsSync(process.env.TRAVIS_PYTHON_PATH)) { + // tslint:disable-next-line:no-unsafe-any + return process.env.TRAVIS_PYTHON_PATH; + } + return 'python'; +} diff --git a/src/test/common/moduleInstaller.test.ts b/src/test/common/moduleInstaller.test.ts index 698d424111a8..31ea81de250a 100644 --- a/src/test/common/moduleInstaller.test.ts +++ b/src/test/common/moduleInstaller.test.ts @@ -21,7 +21,7 @@ import { ITerminalService, ITerminalServiceFactory } from '../../client/common/t import { IConfigurationService, ICurrentProcess, IInstaller, ILogger, IPathUtils, IPersistentStateFactory, IPythonSettings, IsWindows } from '../../client/common/types'; import { ICondaService, IInterpreterLocatorService, IInterpreterService, INTERPRETER_LOCATOR_SERVICE, InterpreterType, PIPENV_SERVICE, PythonInterpreter } from '../../client/interpreter/contracts'; import { IServiceContainer } from '../../client/ioc/types'; -import { rootWorkspaceUri } from '../common'; +import { PYTHON_PATH, rootWorkspaceUri } from '../common'; import { MockModuleInstaller } from '../mocks/moduleInstaller'; import { MockProcessService } from '../mocks/proc'; import { UnitTestIocContainer } from '../unittests/serviceRegistry'; @@ -195,7 +195,7 @@ suite('Module Installer', () => { const interpreter: PythonInterpreter = { type: InterpreterType.Unknown, - path: 'python' + path: PYTHON_PATH }; interpreterService.setup(x => x.getActiveInterpreter(TypeMoq.It.isAny())).returns(() => Promise.resolve(interpreter)); diff --git a/src/test/debugger/attach.ptvsd.test.ts b/src/test/debugger/attach.ptvsd.test.ts index 87d7e77de17d..b5f0f9839e1b 100644 --- a/src/test/debugger/attach.ptvsd.test.ts +++ b/src/test/debugger/attach.ptvsd.test.ts @@ -19,7 +19,7 @@ import { PythonV2DebugConfigurationProvider } from '../../client/debugger'; import { PTVSD_PATH } from '../../client/debugger/Common/constants'; import { AttachRequestArguments, DebugOptions } from '../../client/debugger/Common/Contracts'; import { IServiceContainer } from '../../client/ioc/types'; -import { sleep } from '../common'; +import { PYTHON_PATH, sleep } from '../common'; import { initialize, IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize'; import { continueDebugging, createDebugAdapter } from './utils'; @@ -59,7 +59,7 @@ suite('Attach Debugger - Experimental', () => { // tslint:disable-next-line:no-string-literal env['PYTHONPATH'] = PTVSD_PATH; const pythonArgs = ['-m', 'ptvsd', '--server', '--port', `${port}`, '--file', fileToDebug.fileToCommandArgument()]; - proc = spawn('python', pythonArgs, { env: env, cwd: path.dirname(fileToDebug) }); + proc = spawn(PYTHON_PATH, pythonArgs, { env: env, cwd: path.dirname(fileToDebug) }); await sleep(3000); // Send initialize, attach diff --git a/src/test/debugger/attach.test.ts b/src/test/debugger/attach.test.ts index 5e346c6cb048..7747a0450c01 100644 --- a/src/test/debugger/attach.test.ts +++ b/src/test/debugger/attach.test.ts @@ -12,7 +12,7 @@ import { createDeferred } from '../../client/common/helpers'; import { BufferDecoder } from '../../client/common/process/decoder'; import { ProcessService } from '../../client/common/process/proc'; import { AttachRequestArguments } from '../../client/debugger/Common/Contracts'; -import { sleep } from '../common'; +import { PYTHON_PATH, sleep } from '../common'; import { initialize, IS_APPVEYOR, IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize'; import { DEBUGGER_TIMEOUT } from './common/constants'; @@ -67,7 +67,7 @@ suite('Attach Debugger', () => { // tslint:disable-next-line:no-string-literal customEnv['PYTHONPATH'] = ptvsdPath; const procService = new ProcessService(new BufferDecoder()); - const result = procService.execObservable('python', [fileToDebug, port.toString()], { env: customEnv, cwd: path.dirname(fileToDebug) }); + const result = procService.execObservable(PYTHON_PATH, [fileToDebug, port.toString()], { env: customEnv, cwd: path.dirname(fileToDebug) }); procToKill = result.proc; const expectedOutputs = [ diff --git a/src/test/debugger/capabilities.test.ts b/src/test/debugger/capabilities.test.ts index 5f7f6f53c159..416985681c24 100644 --- a/src/test/debugger/capabilities.test.ts +++ b/src/test/debugger/capabilities.test.ts @@ -20,6 +20,7 @@ import { PTVSD_PATH } from '../../client/debugger/Common/constants'; import { ProtocolParser } from '../../client/debugger/Common/protocolParser'; import { ProtocolMessageWriter } from '../../client/debugger/Common/protocolWriter'; import { PythonDebugger } from '../../client/debugger/mainV2'; +import { PYTHON_PATH } from '../common'; import { IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize'; class Request extends Message implements DebugProtocol.InitializeRequest { @@ -80,7 +81,7 @@ suite('Debugging - Capabilities', () => { const port = await getFreePort({ host, port: 3000 }); const env = { ...process.env }; env.PYTHONPATH = PTVSD_PATH; - proc = spawn('python', ['-m', 'ptvsd', '--server', '--port', `${port}`, '--file', fileToDebug], { cwd: path.dirname(fileToDebug), env }); + proc = spawn(PYTHON_PATH, ['-m', 'ptvsd', '--server', '--port', `${port}`, '--file', fileToDebug], { cwd: path.dirname(fileToDebug), env }); await sleep(3000); const connected = createDeferred(); diff --git a/src/test/debugger/core/capabilities.test.ts b/src/test/debugger/core/capabilities.test.ts deleted file mode 100644 index 63bc7314a0e1..000000000000 --- a/src/test/debugger/core/capabilities.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// 1. Ensure the capabilitites of the debugger sent into the response to initialize matches -// that of the underlying (ptvsd) debugger -// I.e. ensure the response sent by us matches the response sent by ptvsd to the initialize request. diff --git a/src/test/debugger/misc.test.ts b/src/test/debugger/misc.test.ts index 0e17bc9a05c9..995be0db817a 100644 --- a/src/test/debugger/misc.test.ts +++ b/src/test/debugger/misc.test.ts @@ -15,7 +15,7 @@ import { FileSystem } from '../../client/common/platform/fileSystem'; import { PlatformService } from '../../client/common/platform/platformService'; import { PTVSD_PATH } from '../../client/debugger/Common/constants'; import { DebugOptions, LaunchRequestArguments } from '../../client/debugger/Common/Contracts'; -import { sleep } from '../common'; +import { PYTHON_PATH, sleep } from '../common'; import { IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize'; import { DEBUGGER_TIMEOUT } from './common/constants'; import { DebugClientEx } from './debugClient'; @@ -78,7 +78,7 @@ let testCounter = 0; cwd: debugFilesPath, stopOnEntry, debugOptions: [DebugOptions.RedirectOutput], - pythonPath: 'python', + pythonPath: PYTHON_PATH, args: [], env, envFile: '', diff --git a/src/test/debugger/module.test.ts b/src/test/debugger/module.test.ts index cdf88f27a68a..1e51b5e2b030 100644 --- a/src/test/debugger/module.test.ts +++ b/src/test/debugger/module.test.ts @@ -11,7 +11,7 @@ import { EXTENSION_ROOT_DIR } from '../../client/common/constants'; import { noop } from '../../client/common/core.utils'; import { PTVSD_PATH } from '../../client/debugger/Common/constants'; import { DebugOptions, LaunchRequestArguments } from '../../client/debugger/Common/Contracts'; -import { sleep } from '../common'; +import { PYTHON_PATH, sleep } from '../common'; import { IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize'; import { createDebugAdapter } from './utils'; @@ -46,7 +46,7 @@ suite(`Module Debugging - Misc tests: ${debuggerType}`, () => { program: '', cwd: workspaceDirectory, debugOptions: [DebugOptions.RedirectOutput], - pythonPath: 'python', + pythonPath: PYTHON_PATH, args: [], env, envFile: '', diff --git a/src/test/debugger/portAndHost.test.ts b/src/test/debugger/portAndHost.test.ts index 6d2d79491bbf..32fdf3941a74 100644 --- a/src/test/debugger/portAndHost.test.ts +++ b/src/test/debugger/portAndHost.test.ts @@ -9,6 +9,7 @@ import * as path from 'path'; import { DebugClient } from 'vscode-debugadapter-testsupport'; import { noop } from '../../client/common/core.utils'; import { DebugOptions, LaunchRequestArguments } from '../../client/debugger/Common/Contracts'; +import { PYTHON_PATH } from '../common'; import { IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize'; import { DEBUGGER_TIMEOUT } from './common/constants'; @@ -50,7 +51,7 @@ const EXPERIMENTAL_DEBUG_ADAPTER = path.join(__dirname, '..', '..', 'client', 'd cwd: debugFilesPath, stopOnEntry, debugOptions: [DebugOptions.RedirectOutput], - pythonPath: 'python', + pythonPath: PYTHON_PATH, args: [], envFile: '', host, port, diff --git a/src/test/debugger/utils.ts b/src/test/debugger/utils.ts index ad59a2fd98e5..adc4a532221a 100644 --- a/src/test/debugger/utils.ts +++ b/src/test/debugger/utils.ts @@ -69,6 +69,9 @@ export async function validateVariablesInFrame(debugClient: DebugClient, export function makeHttpRequest(uri: string): Promise { return new Promise((resolve, reject) => { request.get(uri, (error: any, response: request.Response, body: any) => { + if (error) { + return reject(error); + } if (response.statusCode !== 200) { reject(new Error(`Status code = ${response.statusCode}`)); } else { diff --git a/src/test/debugger/web.framework.test.ts b/src/test/debugger/web.framework.test.ts new file mode 100644 index 000000000000..ca3ca6c6a19f --- /dev/null +++ b/src/test/debugger/web.framework.test.ts @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +// tslint:disable:no-suspicious-comment max-func-body-length no-invalid-this no-var-requires no-require-imports no-any no-http-string no-string-literal no-console + +import { expect } from 'chai'; +import * as getFreePort from 'get-port'; +import * as path from 'path'; +import { DebugClient } from 'vscode-debugadapter-testsupport'; +import { EXTENSION_ROOT_DIR } from '../../client/common/constants'; +import { noop } from '../../client/common/core.utils'; +import { DebugOptions, LaunchRequestArguments } from '../../client/debugger/Common/Contracts'; +import { PYTHON_PATH, sleep } from '../common'; +import { IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize'; +import { DEBUGGER_TIMEOUT } from './common/constants'; +import { continueDebugging, createDebugAdapter, ExpectedVariable, hitHttpBreakpoint, makeHttpRequest, validateVariablesInFrame } from './utils'; + +let testCounter = 0; +const debuggerType = 'pythonExperimental'; +suite(`Django and Flask Debugging: ${debuggerType}`, () => { + let debugClient: DebugClient; + setup(async function () { + if (!IS_MULTI_ROOT_TEST || !TEST_DEBUGGER) { + this.skip(); + } + this.timeout(5 * DEBUGGER_TIMEOUT); + const coverageDirectory = path.join(EXTENSION_ROOT_DIR, `debug_coverage_django_flask${testCounter += 1}`); + debugClient = await createDebugAdapter(coverageDirectory); + }); + teardown(async () => { + // Wait for a second before starting another test (sometimes, sockets take a while to get closed). + await sleep(1000); + try { + await debugClient.stop().catch(noop); + // tslint:disable-next-line:no-empty + } catch (ex) { } + await sleep(1000); + }); + function buildLaunchArgs(workspaceDirectory: string): LaunchRequestArguments { + const env = {}; + // tslint:disable-next-line:no-string-literal + env['PYTHONPATH'] = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'experimental', 'ptvsd'); + + // tslint:disable-next-line:no-unnecessary-local-variable + const options: LaunchRequestArguments = { + cwd: workspaceDirectory, + program: '', + debugOptions: [DebugOptions.RedirectOutput], + pythonPath: PYTHON_PATH, + args: [], + env, + envFile: '', + logToFile: true, + type: debuggerType + }; + + return options; + } + async function buildFlaskLaunchArgs(workspaceDirectory: string) { + const port = await getFreePort({ host: 'localhost' }); + const options = buildLaunchArgs(workspaceDirectory); + + options.env!['FLASK_APP'] = path.join(workspaceDirectory, 'run.py'); + options.module = 'flask'; + options.debugOptions = [DebugOptions.RedirectOutput, DebugOptions.Jinja]; + options.args = [ + 'run', + '--no-debugger', + '--no-reload', + '--port', + `${port}` + ]; + + return { options, port }; + } + async function buildDjangoLaunchArgs(workspaceDirectory: string) { + const port = await getFreePort({ host: 'localhost' }); + const options = buildLaunchArgs(workspaceDirectory); + + options.program = path.join(workspaceDirectory, 'manage.py'); + options.debugOptions = [DebugOptions.RedirectOutput, DebugOptions.Django]; + options.args = [ + 'runserver', + '--noreload', + '--nothreading', + `${port}` + ]; + + return { options, port }; + } + + async function testTemplateDebugging(launchArgs: LaunchRequestArguments, port: number, viewFile: string, viewLine: number, templateFile: string, templateLine: number) { + await Promise.all([ + debugClient.configurationSequence(), + debugClient.launch(launchArgs), + debugClient.waitForEvent('initialized'), + debugClient.waitForEvent('process'), + debugClient.waitForEvent('thread') + ]); + + const httpResult = await makeHttpRequest(`http://localhost:${port}`); + + expect(httpResult).to.contain('Hello this_is_a_value_from_server'); + expect(httpResult).to.contain('Hello this_is_another_value_from_server'); + + await hitHttpBreakpoint(debugClient, `http://localhost:${port}`, viewFile, viewLine); + + await continueDebugging(debugClient); + await debugClient.setBreakpointsRequest({ breakpoints: [], lines: [], source: { path: viewFile } }); + + // Template debugging. + const [stackTrace, htmlResultPromise] = await hitHttpBreakpoint(debugClient, `http://localhost:${port}`, templateFile, templateLine); + + // Wait for breakpoint to hit + const expectedVariables: ExpectedVariable[] = [ + { name: 'value_from_server', type: 'str', value: '\'this_is_a_value_from_server\'' }, + { name: 'another_value_from_server', type: 'str', value: '\'this_is_another_value_from_server\'' } + ]; + await validateVariablesInFrame(debugClient, stackTrace, expectedVariables, 1); + + await debugClient.setBreakpointsRequest({ breakpoints: [], lines: [], source: { path: templateFile } }); + await continueDebugging(debugClient); + + const htmlResult = await htmlResultPromise; + expect(htmlResult).to.contain('Hello this_is_a_value_from_server'); + expect(htmlResult).to.contain('Hello this_is_another_value_from_server'); + } + + test('Test Flask Route and Template debugging', async () => { + const workspaceDirectory = path.join(EXTENSION_ROOT_DIR, 'src', 'testMultiRootWkspc', 'workspace5', 'flaskApp'); + const { options, port } = await buildFlaskLaunchArgs(workspaceDirectory); + + await testTemplateDebugging(options, port, + path.join(workspaceDirectory, 'run.py'), 7, + path.join(workspaceDirectory, 'templates', 'index.html'), 6); + }); + + test('Test Django Route and Template debugging', async () => { + const workspaceDirectory = path.join(EXTENSION_ROOT_DIR, 'src', 'testMultiRootWkspc', 'workspace5', 'djangoApp'); + const { options, port } = await buildDjangoLaunchArgs(workspaceDirectory); + + await testTemplateDebugging(options, port, + path.join(workspaceDirectory, 'home', 'views.py'), 10, + path.join(workspaceDirectory, 'home', 'templates', 'index.html'), 6); + }); +}); diff --git a/src/test/initialize.ts b/src/test/initialize.ts index 0a428faa4dbd..edaa7324f6ce 100644 --- a/src/test/initialize.ts +++ b/src/test/initialize.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import * as vscode from 'vscode'; import { PythonSettings } from '../client/common/configSettings'; import { activated } from '../client/extension'; -import { clearPythonPathInWorkspaceFolder, resetGlobalPythonPathSetting, setPythonPathInWorkspaceRoot } from './common'; +import { clearPythonPathInWorkspaceFolder, PYTHON_PATH, resetGlobalPythonPathSetting, setPythonPathInWorkspaceRoot } from './common'; export * from './constants'; @@ -16,8 +16,6 @@ const workspace3Uri = vscode.Uri.file(path.join(multirootPath, 'workspace3')); //First thing to be executed. process.env['VSC_PYTHON_CI_TEST'] = '1'; -const PYTHON_PATH = getPythonPath(); - // Ability to use custom python environments for testing export async function initializePython() { await resetGlobalPythonPathSetting(); @@ -54,12 +52,3 @@ export async function closeActiveWindows(): Promise { }, 15000); }); } - -function getPythonPath(): string { - // tslint:disable-next-line:no-unsafe-any - if (process.env.TRAVIS_PYTHON_PATH && fs.existsSync(process.env.TRAVIS_PYTHON_PATH)) { - // tslint:disable-next-line:no-unsafe-any - return process.env.TRAVIS_PYTHON_PATH; - } - return 'python'; -} diff --git a/src/test/interpreters/interpreterVersion.test.ts b/src/test/interpreters/interpreterVersion.test.ts index 6bd728d669ab..9e78d8ee5e66 100644 --- a/src/test/interpreters/interpreterVersion.test.ts +++ b/src/test/interpreters/interpreterVersion.test.ts @@ -7,6 +7,7 @@ import '../../client/common/extensions'; import { IProcessService } from '../../client/common/process/types'; import { IInterpreterVersionService } from '../../client/interpreter/contracts'; import { PIP_VERSION_REGEX } from '../../client/interpreter/interpreterVersion'; +import { PYTHON_PATH } from '../common'; import { initialize, initializeTest } from '../initialize'; import { UnitTestIocContainer } from '../unittests/serviceRegistry'; @@ -31,10 +32,10 @@ suite('Interpreters display version', () => { test('Must return the Python Version', async () => { const pythonProcess = ioc.serviceContainer.get(IProcessService); - const output = await pythonProcess.exec('python', ['--version'], { cwd: __dirname, mergeStdOutErr: true }); + const output = await pythonProcess.exec(PYTHON_PATH, ['--version'], { cwd: __dirname, mergeStdOutErr: true }); const version = output.stdout.splitLines()[0]; const interpreterVersion = ioc.serviceContainer.get(IInterpreterVersionService); - const pyVersion = await interpreterVersion.getVersion('python', 'DEFAULT_TEST_VALUE'); + const pyVersion = await interpreterVersion.getVersion(PYTHON_PATH, 'DEFAULT_TEST_VALUE'); assert.equal(pyVersion, version, 'Incorrect version'); }); test('Must return the default value when Python path is invalid', async () => { @@ -44,7 +45,7 @@ suite('Interpreters display version', () => { }); test('Must return the pip Version', async () => { const pythonProcess = ioc.serviceContainer.get(IProcessService); - const result = await pythonProcess.exec('python', ['-m', 'pip', '--version'], { cwd: __dirname, mergeStdOutErr: true }); + const result = await pythonProcess.exec(PYTHON_PATH, ['-m', 'pip', '--version'], { cwd: __dirname, mergeStdOutErr: true }); const output = result.stdout.splitLines()[0]; // Take the second part, see below example. // pip 9.0.1 from /Users/donjayamanne/anaconda3/lib/python3.6/site-packages (python 3.6). @@ -55,7 +56,7 @@ suite('Interpreters display version', () => { assert.isAtLeast(matches!.length, 1, 'Version number not found'); const interpreterVersion = ioc.serviceContainer.get(IInterpreterVersionService); - const pipVersionPromise = interpreterVersion.getPipVersion('python'); + const pipVersionPromise = interpreterVersion.getPipVersion(PYTHON_PATH); // tslint:disable-next-line:no-non-null-assertion await expect(pipVersionPromise).to.eventually.equal(matches![0].trim()); }); diff --git a/src/test/interpreters/virtualEnvManager.test.ts b/src/test/interpreters/virtualEnvManager.test.ts index bfd498b55de3..3d00204b9269 100644 --- a/src/test/interpreters/virtualEnvManager.test.ts +++ b/src/test/interpreters/virtualEnvManager.test.ts @@ -10,6 +10,7 @@ import { IBufferDecoder, IProcessService } from '../../client/common/process/typ import { VirtualEnvironmentManager } from '../../client/interpreter/virtualEnvs'; import { ServiceContainer } from '../../client/ioc/container'; import { ServiceManager } from '../../client/ioc/serviceManager'; +import { PYTHON_PATH } from '../common'; suite('Virtual environment manager', () => { let serviceManager: ServiceManager; @@ -22,15 +23,15 @@ suite('Virtual environment manager', () => { serviceContainer = new ServiceContainer(cont); }); - test('Plain Python environment suffix', async () => await testSuffix('')); - test('Venv environment suffix', async () => await testSuffix('venv')); - test('Virtualenv Python environment suffix', async () => await testSuffix('virtualenv')); + test('Plain Python environment suffix', async () => testSuffix('')); + test('Venv environment suffix', async () => testSuffix('venv')); + test('Virtualenv Python environment suffix', async () => testSuffix('virtualenv')); test('Run actual virtual env detection code', async () => { serviceManager.addSingleton(IProcessService, ProcessService); serviceManager.addSingleton(IBufferDecoder, BufferDecoder); const venvManager = new VirtualEnvironmentManager(serviceContainer); - const name = await venvManager.getEnvironmentName('python'); + const name = await venvManager.getEnvironmentName(PYTHON_PATH); const result = name === '' || name === 'venv' || name === 'virtualenv'; expect(result).to.be.equal(true, 'Running venv detection code failed.'); }); @@ -41,13 +42,13 @@ suite('Virtual environment manager', () => { const venvManager = new VirtualEnvironmentManager(serviceContainer); process - .setup(x => x.exec('python', TypeMoq.It.isAny())) + .setup(x => x.exec(PYTHON_PATH, TypeMoq.It.isAny())) .returns(() => Promise.resolve({ stdout: expectedName, stderr: '' })); - const name = await venvManager.getEnvironmentName('python'); + const name = await venvManager.getEnvironmentName(PYTHON_PATH); expect(name).to.be.equal(expectedName, 'Virtual envrironment name suffix is incorrect.'); } }); diff --git a/src/test/providers/shebangCodeLenseProvider.test.ts b/src/test/providers/shebangCodeLenseProvider.test.ts index bc89c1761d5e..b1e4a15bd8ae 100644 --- a/src/test/providers/shebangCodeLenseProvider.test.ts +++ b/src/test/providers/shebangCodeLenseProvider.test.ts @@ -1,8 +1,7 @@ import * as assert from 'assert'; import * as child_process from 'child_process'; import * as path from 'path'; -import * as vscode from 'vscode'; -import { CancellationTokenSource } from 'vscode'; +import { CancellationTokenSource, TextDocument, workspace } from 'vscode'; import { IS_WINDOWS, PythonSettings } from '../../client/common/configSettings'; import { ShebangCodeLensProvider } from '../../client/interpreter/display/shebangCodeLensProvider'; import { getFirstNonEmptyLineFromMultilineString } from '../../client/interpreter/helpers'; @@ -91,7 +90,7 @@ suite('Shebang detection', () => { }); async function openFile(fileName: string) { - return vscode.workspace.openTextDocument(fileName); + return workspace.openTextDocument(fileName); } async function getFullyQualifiedPathToInterpreter(pythonPath: string) { return new Promise(resolve => { @@ -101,8 +100,8 @@ suite('Shebang detection', () => { }).catch(() => undefined); } - async function setupCodeLens(document: vscode.TextDocument) { + async function setupCodeLens(document: TextDocument) { const codeLensProvider = new ShebangCodeLensProvider(ioc.serviceContainer); - return await codeLensProvider.provideCodeLenses(document, new CancellationTokenSource().token); + return codeLensProvider.provideCodeLenses(document, new CancellationTokenSource().token); } }); diff --git a/src/test/terminals/codeExecution/djangoShellCodeExect.test.ts b/src/test/terminals/codeExecution/djangoShellCodeExect.test.ts index b6814214abeb..e85da9496e88 100644 --- a/src/test/terminals/codeExecution/djangoShellCodeExect.test.ts +++ b/src/test/terminals/codeExecution/djangoShellCodeExect.test.ts @@ -13,6 +13,7 @@ import { ITerminalService, ITerminalServiceFactory } from '../../../client/commo import { IConfigurationService, IPythonSettings, ITerminalSettings } from '../../../client/common/types'; import { DjangoShellCodeExecutionProvider } from '../../../client/terminals/codeExecution/djangoShellCodeExecution'; import { ICodeExecutionService } from '../../../client/terminals/types'; +import { PYTHON_PATH } from '../../common'; // tslint:disable-next-line:max-func-body-length suite('Terminal - Django Shell Code Execution', () => { @@ -86,7 +87,7 @@ suite('Terminal - Django Shell Code Execution', () => { }); test('Ensure python path is returned as is, when building repl args on Windows', async () => { - const pythonPath = 'python'; + const pythonPath = PYTHON_PATH; const terminalArgs = ['-a', 'b', 'c']; const expectedTerminalArgs = terminalArgs.concat('manage.py', 'shell'); @@ -102,7 +103,7 @@ suite('Terminal - Django Shell Code Execution', () => { }); test('Ensure python path is returned as is, on non Windows', async () => { - const pythonPath = 'python'; + const pythonPath = PYTHON_PATH; const terminalArgs = ['-a', 'b', 'c']; const expectedTerminalArgs = terminalArgs.concat('manage.py', 'shell'); diff --git a/src/test/terminals/codeExecution/terminalCodeExec.test.ts b/src/test/terminals/codeExecution/terminalCodeExec.test.ts index 4466de64354f..2ada071c2f3c 100644 --- a/src/test/terminals/codeExecution/terminalCodeExec.test.ts +++ b/src/test/terminals/codeExecution/terminalCodeExec.test.ts @@ -15,6 +15,7 @@ import { DjangoShellCodeExecutionProvider } from '../../../client/terminals/code import { ReplProvider } from '../../../client/terminals/codeExecution/repl'; import { TerminalCodeExecutionProvider } from '../../../client/terminals/codeExecution/terminalCodeExecution'; import { ICodeExecutionService } from '../../../client/terminals/types'; +import { PYTHON_PATH } from '../../common'; // tslint:disable-next-line:max-func-body-length suite('Terminal Code Execution', () => { @@ -99,7 +100,7 @@ suite('Terminal Code Execution', () => { platform.setup(p => p.isWindows).returns(() => isWindows); platform.setup(p => p.isMac).returns(() => isOsx); platform.setup(p => p.isLinux).returns(() => isLinux); - settings.setup(s => s.pythonPath).returns(() => 'python'); + settings.setup(s => s.pythonPath).returns(() => PYTHON_PATH); terminalSettings.setup(t => t.launchArgs).returns(() => []); await executor.initializeRepl(); @@ -130,12 +131,12 @@ suite('Terminal Code Execution', () => { workspace.setup(w => w.getWorkspaceFolder(TypeMoq.It.isAny())).returns(() => workspaceFolder.object); workspaceFolder.setup(w => w.uri).returns(() => Uri.file(path.join('c', 'path', 'to'))); platform.setup(p => p.isWindows).returns(() => false); - settings.setup(s => s.pythonPath).returns(() => 'python'); + settings.setup(s => s.pythonPath).returns(() => PYTHON_PATH); terminalSettings.setup(t => t.launchArgs).returns(() => []); await executor.executeFile(file); - terminalService.verify(async t => await t.sendText(TypeMoq.It.isValue(`cd ${path.dirname(file.fsPath).fileToCommandArgument()}`)), TypeMoq.Times.once()); + terminalService.verify(async t => t.sendText(TypeMoq.It.isValue(`cd ${path.dirname(file.fsPath).fileToCommandArgument()}`)), TypeMoq.Times.once()); } test('Ensure we set current directory before executing file (non windows)', async () => { await ensureWeSetCurrentDirectoryBeforeExecutingAFile(false); @@ -150,12 +151,12 @@ suite('Terminal Code Execution', () => { workspace.setup(w => w.getWorkspaceFolder(TypeMoq.It.isAny())).returns(() => workspaceFolder.object); workspaceFolder.setup(w => w.uri).returns(() => Uri.file(path.join('c', 'path', 'to'))); platform.setup(p => p.isWindows).returns(() => isWindows); - settings.setup(s => s.pythonPath).returns(() => 'python'); + settings.setup(s => s.pythonPath).returns(() => PYTHON_PATH); terminalSettings.setup(t => t.launchArgs).returns(() => []); await executor.executeFile(file); const dir = path.dirname(file.fsPath).fileToCommandArgument(); - terminalService.verify(async t => await t.sendText(TypeMoq.It.isValue(`cd ${dir}`)), TypeMoq.Times.once()); + terminalService.verify(async t => t.sendText(TypeMoq.It.isValue(`cd ${dir}`)), TypeMoq.Times.once()); } test('Ensure we set current directory (and quote it when containing spaces) before executing file (non windows)', async () => { @@ -172,12 +173,12 @@ suite('Terminal Code Execution', () => { workspace.setup(w => w.getWorkspaceFolder(TypeMoq.It.isAny())).returns(() => workspaceFolder.object); workspaceFolder.setup(w => w.uri).returns(() => Uri.file(path.join('c', 'path', 'to', 'file with spaces in path'))); platform.setup(p => p.isWindows).returns(() => isWindows); - settings.setup(s => s.pythonPath).returns(() => 'python'); + settings.setup(s => s.pythonPath).returns(() => PYTHON_PATH); terminalSettings.setup(t => t.launchArgs).returns(() => []); await executor.executeFile(file); - terminalService.verify(async t => await t.sendText(TypeMoq.It.isAny()), TypeMoq.Times.never()); + terminalService.verify(async t => t.sendText(TypeMoq.It.isAny()), TypeMoq.Times.never()); } test('Ensure we do not set current directory before executing file if in the same directory (non windows)', async () => { await ensureWeDoNotSetCurrentDirectoryBeforeExecutingFileInSameDirectory(false); @@ -191,12 +192,12 @@ suite('Terminal Code Execution', () => { terminalSettings.setup(t => t.executeInFileDir).returns(() => true); workspace.setup(w => w.getWorkspaceFolder(TypeMoq.It.isAny())).returns(() => undefined); platform.setup(p => p.isWindows).returns(() => isWindows); - settings.setup(s => s.pythonPath).returns(() => 'python'); + settings.setup(s => s.pythonPath).returns(() => PYTHON_PATH); terminalSettings.setup(t => t.launchArgs).returns(() => []); await executor.executeFile(file); - terminalService.verify(async t => await t.sendText(TypeMoq.It.isAny()), TypeMoq.Times.never()); + terminalService.verify(async t => t.sendText(TypeMoq.It.isAny()), TypeMoq.Times.never()); } test('Ensure we do not set current directory before executing file if file is not in a workspace (non windows)', async () => { await ensureWeDoNotSetCurrentDirectoryBeforeExecutingFileNotInSameDirectory(false); @@ -215,12 +216,12 @@ suite('Terminal Code Execution', () => { await executor.executeFile(file); const expectedPythonPath = isWindows ? pythonPath.replace(/\\/g, '/') : pythonPath; const expectedArgs = terminalArgs.concat(file.fsPath.fileToCommandArgument()); - terminalService.verify(async t => await t.sendCommand(TypeMoq.It.isValue(expectedPythonPath), TypeMoq.It.isValue(expectedArgs)), TypeMoq.Times.once()); + terminalService.verify(async t => t.sendCommand(TypeMoq.It.isValue(expectedPythonPath), TypeMoq.It.isValue(expectedArgs)), TypeMoq.Times.once()); } test('Ensure python file execution script is sent to terminal on windows', async () => { const file = Uri.file(path.join('c', 'path', 'to', 'file with spaces in path', 'one.py')); - await testFileExecution(true, 'python', [], file); + await testFileExecution(true, PYTHON_PATH, [], file); }); test('Ensure python file execution script is sent to terminal on windows with fully qualified python path', async () => { @@ -230,12 +231,12 @@ suite('Terminal Code Execution', () => { test('Ensure python file execution script is not quoted when no spaces in file path', async () => { const file = Uri.file(path.join('c', 'path', 'to', 'file', 'one.py')); - await testFileExecution(true, 'python', [], file); + await testFileExecution(true, PYTHON_PATH, [], file); }); test('Ensure python file execution script supports custom python arguments', async () => { const file = Uri.file(path.join('c', 'path', 'to', 'file', 'one.py')); - await testFileExecution(false, 'python', ['-a', '-b', '-c'], file); + await testFileExecution(false, PYTHON_PATH, ['-a', '-b', '-c'], file); }); function testReplCommandArguments(isWindows: boolean, pythonPath: string, expectedPythonPath: string, terminalArgs: string[]) { @@ -265,7 +266,7 @@ suite('Terminal Code Execution', () => { }); test('Ensure python path is returned as is, when building repl args on Windows', () => { - const pythonPath = 'python'; + const pythonPath = PYTHON_PATH; const terminalArgs = ['-a', 'b', 'c']; testReplCommandArguments(true, pythonPath, pythonPath, terminalArgs); @@ -279,7 +280,7 @@ suite('Terminal Code Execution', () => { }); test('Ensure python path is returned as is, on non Windows', () => { - const pythonPath = 'python'; + const pythonPath = PYTHON_PATH; const terminalArgs = ['-a', 'b', 'c']; testReplCommandArguments(false, pythonPath, pythonPath, terminalArgs); @@ -291,8 +292,8 @@ suite('Terminal Code Execution', () => { // tslint:disable-next-line:no-any await executor.execute(undefined as any as string); - terminalService.verify(async t => await t.sendCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.never()); - terminalService.verify(async t => await t.sendText(TypeMoq.It.isAny()), TypeMoq.Times.never()); + terminalService.verify(async t => t.sendCommand(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.never()); + terminalService.verify(async t => t.sendText(TypeMoq.It.isAny()), TypeMoq.Times.never()); }); test('Ensure repl is initialized once before sending text to the repl', async () => { @@ -308,7 +309,7 @@ suite('Terminal Code Execution', () => { await executor.execute('cmd3'); const expectedTerminalArgs = isDjangoRepl ? terminalArgs.concat(['manage.py', 'shell']) : terminalArgs; - terminalService.verify(async t => await t.sendCommand(TypeMoq.It.isValue(pythonPath), TypeMoq.It.isValue(expectedTerminalArgs)), TypeMoq.Times.once()); + terminalService.verify(async t => t.sendCommand(TypeMoq.It.isValue(pythonPath), TypeMoq.It.isValue(expectedTerminalArgs)), TypeMoq.Times.once()); }); test('Ensure repl is re-initialized when temrinal is closed', async () => { @@ -334,15 +335,15 @@ suite('Terminal Code Execution', () => { const expectedTerminalArgs = isDjangoRepl ? terminalArgs.concat(['manage.py', 'shell']) : terminalArgs; expect(closeTerminalCallback).not.to.be.an('undefined', 'Callback not initialized'); - terminalService.verify(async t => await t.sendCommand(TypeMoq.It.isValue(pythonPath), TypeMoq.It.isValue(expectedTerminalArgs)), TypeMoq.Times.once()); + terminalService.verify(async t => t.sendCommand(TypeMoq.It.isValue(pythonPath), TypeMoq.It.isValue(expectedTerminalArgs)), TypeMoq.Times.once()); closeTerminalCallback!.call(terminalService.object); await executor.execute('cmd4'); - terminalService.verify(async t => await t.sendCommand(TypeMoq.It.isValue(pythonPath), TypeMoq.It.isValue(expectedTerminalArgs)), TypeMoq.Times.exactly(2)); + terminalService.verify(async t => t.sendCommand(TypeMoq.It.isValue(pythonPath), TypeMoq.It.isValue(expectedTerminalArgs)), TypeMoq.Times.exactly(2)); closeTerminalCallback!.call(terminalService.object); await executor.execute('cmd5'); - terminalService.verify(async t => await t.sendCommand(TypeMoq.It.isValue(pythonPath), TypeMoq.It.isValue(expectedTerminalArgs)), TypeMoq.Times.exactly(3)); + terminalService.verify(async t => t.sendCommand(TypeMoq.It.isValue(pythonPath), TypeMoq.It.isValue(expectedTerminalArgs)), TypeMoq.Times.exactly(3)); }); test('Ensure code is sent to terminal', async () => { @@ -353,10 +354,10 @@ suite('Terminal Code Execution', () => { terminalSettings.setup(t => t.launchArgs).returns(() => terminalArgs); await executor.execute('cmd1'); - terminalService.verify(async t => await t.sendText('cmd1'), TypeMoq.Times.once()); + terminalService.verify(async t => t.sendText('cmd1'), TypeMoq.Times.once()); await executor.execute('cmd2'); - terminalService.verify(async t => await t.sendText('cmd2'), TypeMoq.Times.once()); + terminalService.verify(async t => t.sendText('cmd2'), TypeMoq.Times.once()); }); }); }); diff --git a/src/testMultiRootWkspc/workspace5/djangoApp/home/__init__.py b/src/testMultiRootWkspc/workspace5/djangoApp/home/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/testMultiRootWkspc/workspace5/djangoApp/home/templates/index.html b/src/testMultiRootWkspc/workspace5/djangoApp/home/templates/index.html new file mode 100644 index 000000000000..6ca5107d23d6 --- /dev/null +++ b/src/testMultiRootWkspc/workspace5/djangoApp/home/templates/index.html @@ -0,0 +1,9 @@ + + + + +

Hello {{ value_from_server }}!

+

Hello {{ another_value_from_server }}!

+ + + diff --git a/src/testMultiRootWkspc/workspace5/djangoApp/home/urls.py b/src/testMultiRootWkspc/workspace5/djangoApp/home/urls.py new file mode 100644 index 000000000000..70a9606e88e6 --- /dev/null +++ b/src/testMultiRootWkspc/workspace5/djangoApp/home/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url('', views.index, name='index'), +] diff --git a/src/testMultiRootWkspc/workspace5/djangoApp/home/views.py b/src/testMultiRootWkspc/workspace5/djangoApp/home/views.py new file mode 100644 index 000000000000..0494f868dc6f --- /dev/null +++ b/src/testMultiRootWkspc/workspace5/djangoApp/home/views.py @@ -0,0 +1,10 @@ +from django.shortcuts import render +from django.template import loader + + +def index(request): + context = { + 'value_from_server':'this_is_a_value_from_server', + 'another_value_from_server':'this_is_another_value_from_server' + } + return render(request, 'index.html', context) diff --git a/src/testMultiRootWkspc/workspace5/djangoApp/manage.py b/src/testMultiRootWkspc/workspace5/djangoApp/manage.py new file mode 100644 index 000000000000..afbc784aafd8 --- /dev/null +++ b/src/testMultiRootWkspc/workspace5/djangoApp/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django + except ImportError: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) + raise + execute_from_command_line(sys.argv) diff --git a/src/testMultiRootWkspc/workspace5/djangoApp/mysite/__init__.py b/src/testMultiRootWkspc/workspace5/djangoApp/mysite/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/testMultiRootWkspc/workspace5/djangoApp/mysite/settings.py b/src/testMultiRootWkspc/workspace5/djangoApp/mysite/settings.py new file mode 100644 index 000000000000..4e182517ca2a --- /dev/null +++ b/src/testMultiRootWkspc/workspace5/djangoApp/mysite/settings.py @@ -0,0 +1,93 @@ +""" +Django settings for mysite project. + +Generated by 'django-admin startproject' using Django 1.11.2. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.11/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '5u06*)07dvd+=kn)zqp8#b0^qt@*$8=nnjc&&0lzfc28(wns&l' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['localhost', '127.0.0.1'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.contenttypes', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ +] + +ROOT_URLCONF = 'mysite.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': ['home/templates'], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'mysite.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.11/ref/settings/#databases + +DATABASES = { +} + + +# Password validation +# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.11/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.11/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/src/testMultiRootWkspc/workspace5/djangoApp/mysite/urls.py b/src/testMultiRootWkspc/workspace5/djangoApp/mysite/urls.py new file mode 100644 index 000000000000..9db383365e3e --- /dev/null +++ b/src/testMultiRootWkspc/workspace5/djangoApp/mysite/urls.py @@ -0,0 +1,23 @@ +"""mysite URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.11/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.conf.urls import url, include + 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) +""" +from django.conf.urls import url, include +from django.contrib import admin +from django.views.generic import RedirectView + +urlpatterns = [ + url(r'^home/', include('home.urls')), + url('', RedirectView.as_view(url='/home/')), +] diff --git a/src/testMultiRootWkspc/workspace5/djangoApp/mysite/wsgi.py b/src/testMultiRootWkspc/workspace5/djangoApp/mysite/wsgi.py new file mode 100644 index 000000000000..74e7daeefe76 --- /dev/null +++ b/src/testMultiRootWkspc/workspace5/djangoApp/mysite/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for mysite project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + +application = get_wsgi_application() diff --git a/src/testMultiRootWkspc/workspace5/flaskApp/run.py b/src/testMultiRootWkspc/workspace5/flaskApp/run.py new file mode 100644 index 000000000000..9c3172c3e918 --- /dev/null +++ b/src/testMultiRootWkspc/workspace5/flaskApp/run.py @@ -0,0 +1,13 @@ +from flask import Flask, render_template +app = Flask(__name__) + + +@app.route('/') +def hello(): + return render_template('index.html', + value_from_server='this_is_a_value_from_server', + another_value_from_server='this_is_another_value_from_server') + + +if __name__ == '__main__': + app.run() diff --git a/src/testMultiRootWkspc/workspace5/flaskApp/templates/index.html b/src/testMultiRootWkspc/workspace5/flaskApp/templates/index.html new file mode 100644 index 000000000000..6ca5107d23d6 --- /dev/null +++ b/src/testMultiRootWkspc/workspace5/flaskApp/templates/index.html @@ -0,0 +1,9 @@ + + + + +

Hello {{ value_from_server }}!

+

Hello {{ another_value_from_server }}!

+ + +