Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f22924c
Update tpn distro and 3rd party notices
DonJayamanne Mar 19, 2019
46d4d02
Pin to beta version of PTVSD (#4836)
DonJayamanne Mar 19, 2019
095e210
Add ignore button to the MacInterpreterSelectedAndNoOtherInterpreters…
alinalobast Mar 20, 2019
d180c9c
Generalize test results service (#4813)
Mar 19, 2019
aa2c0ba
Merge branch 'release' of https://github.com/Microsoft/vscode-python …
DonJayamanne Mar 20, 2019
369397c
fix names for run above and run below code lenses (#4879)
IanMatthewHuff Mar 21, 2019
f7a4d53
Fix multiline comments with text on first line. (#4884)
rchiodo Mar 21, 2019
0d96d3a
Cherry-pick 26a7b9c
rchiodo Mar 22, 2019
2412a58
cherry pick from master branch
IanMatthewHuff Mar 22, 2019
76eb5e2
Revert "Revert "Always use the same jedi environment (#4687)" (#4850)"
DonJayamanne Mar 22, 2019
4e44f6d
Update change log entries
DonJayamanne Mar 25, 2019
434567e
Bump ptvsd to 4.2.5 (#4904)
DonJayamanne Mar 25, 2019
6c9b79c
Ensure output panel does not steal focus due to ls errors (#4919)
DonJayamanne Mar 26, 2019
3e314b6
Fix change log
DonJayamanne Mar 26, 2019
d852809
Bump pinned version of Language Server
DonJayamanne Mar 26, 2019
c0f7eca
Release for march 2018 (#4931)
DonJayamanne Mar 26, 2019
1f600d9
Same logic for stable and beta (#4964)
DonJayamanne Mar 27, 2019
095b74c
Point release for March 2018 (#4965)
DonJayamanne Mar 27, 2019
7c041fd
Capture telemetry when tests are disabled (#4997)
DonJayamanne Mar 28, 2019
68316a0
Update change log
DonJayamanne Mar 28, 2019
1738841
March 2019 point release with debugger fixes (#5056)
DonJayamanne Apr 2, 2019
4d1ad28
Point release with fixes for Debugger (#5160)
DonJayamanne Apr 8, 2019
2a0c89f
Track telemetry when switching to and from LS (#5164)
DonJayamanne Apr 8, 2019
106d0b9
Bump language server
DonJayamanne Apr 8, 2019
c6ee732
Merge branch 'release' of https://github.com/Microsoft/vscode-python …
DonJayamanne Apr 8, 2019
e4c1f75
Bump extension version
DonJayamanne Apr 8, 2019
6cda7a3
Merge branch 'release' into mergeRelease3
DonJayamanne Apr 8, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
# Changelog


## 2019.3.3 (8 April 2019)

### Fixes

1. Update ptvsd to [4.2.7](https://github.com/Microsoft/ptvsd/releases/tag/v4.2.7).
* Fix issues related to debugging Django templagtes.
1. Update the Python language server to 0.2.47.

### Code Health

1. Capture telemetry to track switching to and from the Language Server.
([#5162](https://github.com/Microsoft/vscode-python/issues/5162))


## 2019.3.2 (2 April 2019)

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"displayName": "Python",
"description": "Linting, Debugging (multi-threaded, remote), Intellisense, code formatting, refactoring, unit tests, snippets, and more.",
"version": "2019.4.0-alpha",
"languageServerVersion": "0.2.31",
"languageServerVersion": "0.2.47",
"publisher": "ms-python",
"author": {
"name": "Microsoft Corporation"
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
jedi==0.12.0
parso==0.2.1
isort==4.3.4
ptvsd==4.2.6
ptvsd==4.2.7
24 changes: 20 additions & 4 deletions src/client/activation/activationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { IDiagnosticsService } from '../application/diagnostics/types';
import { IApplicationShell, ICommandManager, IWorkspaceService } from '../common/application/types';
import { STANDARD_OUTPUT_CHANNEL } from '../common/constants';
import '../common/extensions';
import { IConfigurationService, IDisposableRegistry, IOutputChannel, IPythonSettings, Resource } from '../common/types';
import { IConfigurationService, IDisposableRegistry, IOutputChannel, IPersistentStateFactory, IPythonSettings, Resource } from '../common/types';
import { swallowExceptions } from '../common/utils/decorators';
import { IServiceContainer } from '../ioc/types';
import { sendTelemetryEvent } from '../telemetry';
import { EventName } from '../telemetry/constants';
Expand All @@ -31,7 +32,8 @@ export class LanguageServerExtensionActivationService implements IExtensionActiv
private readonly lsNotSupportedDiagnosticService: IDiagnosticsService;
private resource!: Resource;

constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer,
@inject(IPersistentStateFactory) private stateFactory: IPersistentStateFactory) {
this.workspaceService = this.serviceContainer.get<IWorkspaceService>(IWorkspaceService);
this.output = this.serviceContainer.get<OutputChannel>(IOutputChannel, STANDARD_OUTPUT_CHANNEL);
this.appShell = this.serviceContainer.get<IApplicationShell>(IApplicationShell);
Expand Down Expand Up @@ -98,7 +100,19 @@ export class LanguageServerExtensionActivationService implements IExtensionActiv
this.currentActivator.activator.dispose();
}
}

@swallowExceptions('Switch Language Server')
public async trackLangaugeServerSwitch(jediEnabled: boolean): Promise<void> {
const state = this.stateFactory.createGlobalPersistentState<boolean | undefined>('SWITCH_LS', undefined);
if (typeof state.value !== 'boolean') {
await state.updateValue(jediEnabled);
return;
}
if (state.value !== jediEnabled) {
await state.updateValue(jediEnabled);
const message = jediEnabled ? 'Switch to Jedi from LS' : 'Switch to LS from Jedi';
sendTelemetryEvent(EventName.PYTHON_LANGUAGE_SERVER_SWITCHED, undefined, { change: message });
}
}
protected onWorkspaceFoldersChanged() {
//If an activated workspace folder was removed, dispose its activator
const workspaceKeys = this.workspaceService.workspaceFolders!.map(workspaceFolder => this.getWorkspacePathKey(workspaceFolder.uri));
Expand Down Expand Up @@ -141,7 +155,9 @@ export class LanguageServerExtensionActivationService implements IExtensionActiv
}
private useJedi(): boolean {
const configurationService = this.serviceContainer.get<IConfigurationService>(IConfigurationService);
return configurationService.getSettings(this.resource).jediEnabled;
const enabled = configurationService.getSettings(this.resource).jediEnabled;
this.trackLangaugeServerSwitch(enabled).ignoreErrors();
return enabled;
}
private getWorkspacePathKey(resource: Resource): string {
return this.workspaceService.getWorkspaceFolderIdentifier(resource, workspacePathNameForGlobalWorkspaces);
Expand Down
1 change: 1 addition & 0 deletions src/client/telemetry/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export enum EventName {
UNITTEST_NAVIGATE_TEST_FUNCTION = 'UNITTEST.NAVIGATE.TEST_FUNCTION',
UNITTEST_NAVIGATE_TEST_SUITE = 'UNITTEST.NAVIGATE.TEST_SUITE',
UNITTEST_EXPLORER_WORK_SPACE_COUNT = 'UNITTEST.TEST_EXPLORER.WORK_SPACE_COUNT',
PYTHON_LANGUAGE_SERVER_SWITCHED = 'PYTHON_LANGUAGE_SERVER.SWITCHED',
PYTHON_LANGUAGE_SERVER_ANALYSISTIME = 'PYTHON_LANGUAGE_SERVER.ANALYSIS_TIME',
PYTHON_LANGUAGE_SERVER_ENABLED = 'PYTHON_LANGUAGE_SERVER.ENABLED',
PYTHON_LANGUAGE_SERVER_EXTRACTED = 'PYTHON_LANGUAGE_SERVER.EXTRACTED',
Expand Down
1 change: 1 addition & 0 deletions src/client/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ export interface IEventNamePropertyMapping {
[EventName.PYTHON_INTERPRETER_ACTIVATION_FOR_TERMINAL]: InterpreterActivation;
[EventName.PYTHON_INTERPRETER_AUTO_SELECTION]: InterpreterAutoSelection;
[EventName.PYTHON_INTERPRETER_DISCOVERY]: InterpreterDiscovery;
[EventName.PYTHON_LANGUAGE_SERVER_SWITCHED]: { change: 'Switch to Jedi from LS' | 'Switch to LS from Jedi' };
[EventName.PYTHON_LANGUAGE_SERVER_ANALYSISTIME]: { success: boolean };
[EventName.PYTHON_LANGUAGE_SERVER_DOWNLOADED]: LanguageServerVersionTelemetry;
[EventName.PYTHON_LANGUAGE_SERVER_ENABLED]: never | undefined;
Expand Down
67 changes: 53 additions & 14 deletions src/test/activation/activationService.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import { LSNotSupportedDiagnosticServiceId } from '../../client/application/diag
import { IDiagnostic, IDiagnosticsService } from '../../client/application/diagnostics/types';
import { IApplicationShell, ICommandManager, IWorkspaceService } from '../../client/common/application/types';
import { IPlatformService } from '../../client/common/platform/types';
import { IConfigurationService, IDisposable, IDisposableRegistry, IOutputChannel, IPythonSettings, Resource } from '../../client/common/types';
import { IConfigurationService, IDisposable, IDisposableRegistry, IOutputChannel, IPersistentState, IPersistentStateFactory, IPythonSettings, Resource } from '../../client/common/types';
import { IServiceContainer } from '../../client/ioc/types';

// tslint:disable:no-any

suite('Activation - ActivationService', () => {
[true, false].forEach(jediIsEnabled => {
suite(`Jedi is ${jediIsEnabled ? 'enabled' : 'disabled'}`, () => {
Expand All @@ -34,12 +36,16 @@ suite('Activation - ActivationService', () => {
let workspaceService: TypeMoq.IMock<IWorkspaceService>;
let platformService: TypeMoq.IMock<IPlatformService>;
let lsNotSupportedDiagnosticService: TypeMoq.IMock<IDiagnosticsService>;
let stateFactory: TypeMoq.IMock<IPersistentStateFactory>;
let state: TypeMoq.IMock<IPersistentState<boolean | undefined>>;
setup(() => {
serviceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
appShell = TypeMoq.Mock.ofType<IApplicationShell>();
workspaceService = TypeMoq.Mock.ofType<IWorkspaceService>();
cmdManager = TypeMoq.Mock.ofType<ICommandManager>();
platformService = TypeMoq.Mock.ofType<IPlatformService>();
stateFactory = TypeMoq.Mock.ofType<IPersistentStateFactory>();
state = TypeMoq.Mock.ofType<IPersistentState<boolean | undefined>>();
const configService = TypeMoq.Mock.ofType<IConfigurationService>();
pythonSettings = TypeMoq.Mock.ofType<IPythonSettings>();
const langFolderServiceMock = TypeMoq.Mock.ofType<ILanguageServerFolderService>();
Expand All @@ -54,7 +60,10 @@ suite('Activation - ActivationService', () => {
langFolderServiceMock
.setup(l => l.getCurrentLanguageServerDirectory())
.returns(() => Promise.resolve(folderVer));

stateFactory.setup(f => f.createGlobalPersistentState(TypeMoq.It.isValue('SWITCH_LS'), TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.returns(() => state.object);
state.setup(s => s.value).returns(() => undefined);
state.setup(s => s.updateValue(TypeMoq.It.isAny())).returns(() => Promise.resolve());
const output = TypeMoq.Mock.ofType<IOutputChannel>();
serviceContainer
.setup(c => c.get(TypeMoq.It.isValue(IOutputChannel), TypeMoq.It.isAny()))
Expand Down Expand Up @@ -101,7 +110,7 @@ suite('Activation - ActivationService', () => {
if (lsSupported && !jediIsEnabled) {
activatorName = LanguageServerActivator.DotNet;
}
let diagnostics : IDiagnostic[];
let diagnostics: IDiagnostic[];
if (!lsSupported && !jediIsEnabled) {
diagnostics = [TypeMoq.It.isAny()];
} else {
Expand All @@ -127,29 +136,29 @@ suite('Activation - ActivationService', () => {
test('LS is supported', async () => {
pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabled);
const activator = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);

await testActivation(activationService, activator, true);
});
test('LS is not supported', async () => {
pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabled);
const activator = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);

await testActivation(activationService, activator, false);
});

test('Activatory must be activated', async () => {
pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabled);
const activator = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);

await testActivation(activationService, activator);
});
test('Activatory must be deactivated', async () => {
pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabled);
const activator = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);

await testActivation(activationService, activator);

Expand All @@ -171,7 +180,7 @@ suite('Activation - ActivationService', () => {

pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabledValueInSetting);
const activator = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);

workspaceService.verifyAll();
await testActivation(activationService, activator);
Expand Down Expand Up @@ -208,7 +217,7 @@ suite('Activation - ActivationService', () => {

pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabledValueInSetting);
const activator = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);

workspaceService.verifyAll();
await testActivation(activationService, activator);
Expand Down Expand Up @@ -244,7 +253,7 @@ suite('Activation - ActivationService', () => {

pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabled);
const activator = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);

workspaceService.verifyAll();
await testActivation(activationService, activator);
Expand Down Expand Up @@ -279,7 +288,7 @@ suite('Activation - ActivationService', () => {

pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabled);
const activator = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);

workspaceService.verifyAll();
await testActivation(activationService, activator);
Expand All @@ -304,12 +313,42 @@ suite('Activation - ActivationService', () => {
appShell.verifyAll();
cmdManager.verifyAll();
});
test('Track current LS usage for first usage', async () => {
state.reset();
state.setup(s => s.value).returns(() => undefined).verifiable(TypeMoq.Times.once());
state.setup(s => s.updateValue(TypeMoq.It.isValue(true))).returns(() => Promise.resolve()).verifiable(TypeMoq.Times.once());

const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);
await activationService.trackLangaugeServerSwitch(true);

state.verifyAll();
});
test('Track switch to LS', async () => {
state.reset();
state.setup(s => s.value).returns(() => true).verifiable(TypeMoq.Times.once());
state.setup(s => s.updateValue(TypeMoq.It.isValue(false))).returns(() => Promise.resolve()).verifiable(TypeMoq.Times.once());

const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);
await activationService.trackLangaugeServerSwitch(false);

state.verify(s => s.updateValue(TypeMoq.It.isValue(false)), TypeMoq.Times.once());
});
test('Track switch to Jedi', async () => {
state.reset();
state.setup(s => s.value).returns(() => false).verifiable(TypeMoq.Times.once());
state.setup(s => s.updateValue(TypeMoq.It.isValue(true))).returns(() => Promise.resolve()).verifiable(TypeMoq.Times.once());

const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);
await activationService.trackLangaugeServerSwitch(true);

state.verify(s => s.updateValue(TypeMoq.It.isValue(true)), TypeMoq.Times.once());
});
if (!jediIsEnabled) {
test('Revert to jedi when LS activation fails', async () => {
pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabled);
const activatorDotNet = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activatorJedi = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);
const diagnostics: IDiagnostic[] = [];
lsNotSupportedDiagnosticService
.setup(l => l.diagnose(undefined))
Expand Down Expand Up @@ -388,7 +427,7 @@ suite('Activation - ActivationService', () => {
.callback(cb => (workspaceFoldersChangedHandler = cb))
.returns(() => TypeMoq.Mock.ofType<IDisposable>().object)
.verifiable(TypeMoq.Times.once());
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);
workspaceService.verifyAll();
expect(workspaceFoldersChangedHandler).not.to.be.equal(undefined, 'Handler not set');
const folder1 = { name: 'one', uri: Uri.parse('one'), index: 1 };
Expand Down Expand Up @@ -430,7 +469,7 @@ suite('Activation - ActivationService', () => {
test('Jedi is only activated once', async () => {
pythonSettings.setup(p => p.jediEnabled).returns(() => jediIsEnabled);
const activator1 = TypeMoq.Mock.ofType<ILanguageServerActivator>();
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object);
const activationService = new LanguageServerExtensionActivationService(serviceContainer.object, stateFactory.object);
const folder1 = { name: 'one', uri: Uri.parse('one'), index: 1 };
const folder2 = { name: 'two', uri: Uri.parse('two'), index: 2 };
serviceContainer
Expand Down