Skip to content

Commit b72ff96

Browse files
authored
Enable Python 3.7 in Linux (#2082)
- Hover over capitalize() text changes in 3.7 - handle floating promise problem (was missing await) - add -k to array in unittest/argsService - pycodestyle is writing future warning to stderr - Add `getMajorMinorVerString` and `getMajorMinorVersion` unittest method - More specific version-test logic for Black test
1 parent f7b5c4f commit b72ff96

11 files changed

Lines changed: 118 additions & 48 deletions

File tree

.travis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ matrix:
3030
- os: linux
3131
python: "3.6-dev"
3232
env: PERFORMANCE_TEST=true
33+
- os: linux
34+
python: "3.7-dev"
35+
env: DEBUGGER_TEST=true
36+
- os: linux
37+
python: "3.7-dev"
38+
env: DEBUGGER_TEST_RELEASE=true
39+
- os: linux
40+
python: "3.7-dev"
41+
env: SINGLE_WORKSPACE_TEST=true
42+
- os: linux
43+
python: "3.7-dev"
44+
env: MULTIROOT_WORKSPACE_TEST=true
3345
allow_failures:
3446
- os: linux
3547
python: "2.7"
@@ -43,6 +55,12 @@ matrix:
4355
- os: linux
4456
python: "3.6-dev"
4557
env: DEBUGGER_TEST_RELEASE=true
58+
- os: linux
59+
python: "3.7-dev"
60+
env: DEBUGGER_TEST=true
61+
- os: linux
62+
python: "3.7-dev"
63+
env: DEBUGGER_TEST_RELEASE=true
4664
before_install: |
4765
if [ $TRAVIS_OS_NAME == "linux" ]; then
4866
export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0;

src/client/formatters/baseFormatter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export abstract class BaseFormatter {
5757
const executionInfo = this.helper.getExecutionInfo(this.product, args, document.uri);
5858
executionInfo.args.push(tempFile);
5959
const pythonToolsExecutionService = this.serviceContainer.get<IPythonToolExecutionService>(IPythonToolExecutionService);
60-
const promise = pythonToolsExecutionService.exec(executionInfo, { cwd, throwOnStdErr: true, token }, document.uri)
60+
const promise = pythonToolsExecutionService.exec(executionInfo, { cwd, throwOnStdErr: false, token }, document.uri)
6161
.then(output => output.stdout)
6262
.then(data => {
6363
if (this.checkCancellation(document.fileName, tempFile, token)) {

src/client/linters/baseLinter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export abstract class BaseLinter implements ILinter {
108108
const cwd = this.getWorkspaceRootPath(document);
109109
const pythonToolsExecutionService = this.serviceContainer.get<IPythonToolExecutionService>(IPythonToolExecutionService);
110110
try {
111-
const result = await pythonToolsExecutionService.exec(executionInfo, { cwd, token: cancellation, mergeStdOutErr: true }, document.uri);
111+
const result = await pythonToolsExecutionService.exec(executionInfo, { cwd, token: cancellation, mergeStdOutErr: false }, document.uri);
112112
this.displayLinterResultHeader(result.stdout);
113113
return await this.parseMessages(result.stdout, document, cancellation, regEx);
114114
} catch (error) {

src/client/unittests/common/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,8 @@ export const IXUnitParser = Symbol('IXUnitParser');
271271
export interface IXUnitParser {
272272
updateResultsFromXmlLogFile(tests: Tests, outputXmlFile: string, passCalculationFormulae: PassCalculationFormulae): Promise<void>;
273273
}
274+
275+
export type PythonVersionInformation = {
276+
major: number;
277+
minor: number;
278+
};

src/client/unittests/unittest/services/argsService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { inject, injectable } from 'inversify';
77
import { IServiceContainer } from '../../../ioc/types';
88
import { IArgumentsHelper, IArgumentsService, TestFilter } from '../../types';
99

10-
const OptionsWithArguments = ['-p', '-s', '-t', '--pattern',
10+
const OptionsWithArguments = ['-k', '-p', '-s', '-t', '--pattern',
1111
'--start-directory', '--top-level-directory'];
1212

1313
const OptionsWithoutArguments = ['-b', '-c', '-f', '-h', '-q', '-v',

src/test/definitions/hover.jedi.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const fileThree = path.join(autoCompPath, 'three.py');
1313
const fileEncoding = path.join(autoCompPath, 'four.py');
1414
const fileEncodingUsed = path.join(autoCompPath, 'five.py');
1515
const fileHover = path.join(autoCompPath, 'hoverTest.py');
16-
const fileStringFormat = path.join(hoverPath, 'stringFormat.py');
16+
const fileStringFormat = path.join(hoverPath, 'functionHover.py');
1717

1818
// tslint:disable-next-line:max-func-body-length
1919
suite('Hover Definition (Jedi)', () => {
@@ -264,20 +264,20 @@ suite('Hover Definition (Jedi)', () => {
264264
}).then(done, done);
265265
});
266266

267-
test('format().capitalize()', async () => {
267+
test('Hover over method shows proper text.', async () => {
268268
const textDocument = await vscode.workspace.openTextDocument(fileStringFormat);
269269
await vscode.window.showTextDocument(textDocument);
270-
const position = new vscode.Position(5, 41);
270+
const position = new vscode.Position(8, 4);
271271
const def = (await vscode.commands.executeCommand<vscode.Hover[]>('vscode.executeHoverProvider', textDocument.uri, position))!;
272272
assert.equal(def.length, 1, 'Definition length is incorrect');
273273
assert.equal(def[0].contents.length, 1, 'Only expected one result');
274274
const contents = normalizeMarkedString(def[0].contents[0]);
275-
if (contents.indexOf('def capitalize') === -1) {
276-
assert.fail(contents, '', '\'def capitalize\' is missing', 'compare');
275+
if (contents.indexOf('def my_func') === -1) {
276+
assert.fail(contents, '', '\'def my_func\' is missing', 'compare');
277277
}
278-
if (contents.indexOf('Return a capitalized version of S') === -1 &&
279-
contents.indexOf('Return a copy of the string S with only its first character') === -1) {
280-
assert.fail(contents, '', '\'Return a capitalized version of S/Return a copy of the string S with only its first character\' message missing', 'compare');
278+
if (contents.indexOf('This is a test.') === -1 &&
279+
contents.indexOf('It also includes this text, too.') === -1) {
280+
assert.fail(contents, '', 'Expected custom function text missing', 'compare');
281281
}
282282
});
283283
});

src/test/format/extension.format.test.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as fs from 'fs-extra';
22
import * as path from 'path';
3-
import * as vscode from 'vscode';
43
import { CancellationTokenSource, Position, Uri, window, workspace } from 'vscode';
54
import { IProcessServiceFactory, IPythonExecutionFactory } from '../../client/common/process/types';
65
import { AutoPep8Formatter } from '../../client/formatters/autoPep8Formatter';
76
import { BlackFormatter } from '../../client/formatters/blackFormatter';
87
import { YapfFormatter } from '../../client/formatters/yapfFormatter';
8+
import { PythonVersionInformation } from '../../client/unittests/common/types';
99
import { closeActiveWindows, initialize, initializeTest } from '../initialize';
1010
import { MockProcessService } from '../mocks/proc';
1111
import { compareFiles } from '../textUtils';
@@ -36,8 +36,8 @@ suite('Formatting', () => {
3636
fs.copySync(originalUnformattedFile, file, { overwrite: true });
3737
});
3838
fs.ensureDirSync(path.dirname(autoPep8FileToFormat));
39-
const pythonProcess = await ioc.serviceContainer.get<IPythonExecutionFactory>(IPythonExecutionFactory).create({ resource: vscode.Uri.file(workspaceRootPath) });
40-
const py2 = await ioc.getPythonMajorVersion(vscode.Uri.parse(originalUnformattedFile)) === 2;
39+
const pythonProcess = await ioc.serviceContainer.get<IPythonExecutionFactory>(IPythonExecutionFactory).create({ resource: Uri.file(workspaceRootPath) });
40+
const py2 = await ioc.getPythonMajorVersion(Uri.parse(originalUnformattedFile)) === 2;
4141
const yapf = pythonProcess.execModule('yapf', [originalUnformattedFile], { cwd: workspaceRootPath });
4242
const autoPep8 = pythonProcess.execModule('autopep8', [originalUnformattedFile], { cwd: workspaceRootPath });
4343
const formatters = [yapf, autoPep8];
@@ -99,26 +99,34 @@ suite('Formatting', () => {
9999
}
100100

101101
async function testFormatting(formatter: AutoPep8Formatter | BlackFormatter | YapfFormatter, formattedContents: string, fileToFormat: string, outputFileName: string) {
102-
const textDocument = await vscode.workspace.openTextDocument(fileToFormat);
103-
const textEditor = await vscode.window.showTextDocument(textDocument);
102+
const textDocument = await workspace.openTextDocument(fileToFormat);
103+
const textEditor = await window.showTextDocument(textDocument);
104104
const options = { insertSpaces: textEditor.options.insertSpaces! as boolean, tabSize: textEditor.options.tabSize! as number };
105105

106106
await injectFormatOutput(outputFileName);
107107

108-
const edits = await formatter.formatDocument(textDocument, options, new vscode.CancellationTokenSource().token);
108+
const edits = await formatter.formatDocument(textDocument, options, new CancellationTokenSource().token);
109109
await textEditor.edit(editBuilder => {
110110
edits.forEach(edit => editBuilder.replace(edit.range, edit.newText));
111111
});
112112
compareFiles(formattedContents, textEditor.document.getText());
113113
}
114114

115-
test('AutoPep8', async () => testFormatting(new AutoPep8Formatter(ioc.serviceContainer), formattedAutoPep8, autoPep8FileToFormat, 'autopep8.output'));
115+
test('AutoPep8', async () => {
116+
await testFormatting(
117+
new AutoPep8Formatter(ioc.serviceContainer),
118+
formattedAutoPep8,
119+
autoPep8FileToFormat,
120+
'autopep8.output');
121+
});
122+
// tslint:disable-next-line:no-function-expression
116123
test('Black', async function () {
117-
if (await ioc.getPythonMajorVersion(vscode.Uri.parse(blackFileToFormat)) === 2) {
124+
const pyVersion: PythonVersionInformation = await ioc.getPythonMajorMinorVersion(Uri.parse(blackFileToFormat));
125+
126+
if (pyVersion && (pyVersion.major < 3 || (pyVersion.major === 3 && pyVersion.minor < 6))) {
118127
// tslint:disable-next-line:no-invalid-this
119128
return this.skip();
120129
}
121-
122130
await testFormatting(new BlackFormatter(ioc.serviceContainer), formattedBlack, blackFileToFormat, 'black.output');
123131
});
124132
test('Yapf', async () => testFormatting(new YapfFormatter(ioc.serviceContainer), formattedYapf, yapfFileToFormat, 'yapf.output'));
@@ -154,7 +162,7 @@ suite('Formatting', () => {
154162

155163
const options = { insertSpaces: textEditor.options.insertSpaces! as boolean, tabSize: 1 };
156164
const formatter = new YapfFormatter(ioc.serviceContainer);
157-
const edits = await formatter.formatDocument(textDocument, options, new vscode.CancellationTokenSource().token);
165+
const edits = await formatter.formatDocument(textDocument, options, new CancellationTokenSource().token);
158166
await textEditor.edit(editBuilder => {
159167
edits.forEach(edit => editBuilder.replace(edit.range, edit.newText));
160168
});

src/test/linters/lint.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ const filteredPep88MessagesToBeReturned: ILintMessage[] = [
9595
];
9696

9797
// tslint:disable-next-line:max-func-body-length
98-
suite('Linting', () => {
98+
suite('Linting - General Tests', () => {
9999
let ioc: UnitTestIocContainer;
100100
let linterManager: ILinterManager;
101101
let configService: IConfigurationService;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
def my_func():
2+
"""
3+
This is a test.
4+
5+
It also includes this text, too.
6+
"""
7+
pass
8+
9+
my_func()

src/test/refactor/extension.refactor.extract.var.test.ts

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
import * as assert from 'assert';
44
import * as fs from 'fs-extra';
55
import * as path from 'path';
6-
import * as vscode from 'vscode';
7-
import { Position } from 'vscode';
6+
import { commands, Position, Range, Selection, TextEditorCursorStyle, TextEditorLineNumbersStyle, TextEditorOptions, Uri, window, workspace } from 'vscode';
87
import { PythonSettings } from '../../client/common/configSettings';
98
import { getTextEditsFromPatch } from '../../client/common/editor';
109
import { extractVariable } from '../../client/providers/simpleRefactorProvider';
1110
import { RefactorProxy } from '../../client/refactor/proxy';
11+
import { PythonVersionInformation } from '../../client/unittests/common/types';
12+
import { rootWorkspaceUri } from '../common';
1213
import { UnitTestIocContainer } from '../unittests/serviceRegistry';
1314
import { closeActiveWindows, initialize, initializeTest, IS_CI_SERVER } from './../initialize';
1415
import { MockOutputChannel } from './../mockClasses';
@@ -23,24 +24,24 @@ interface RenameResponse {
2324

2425
suite('Variable Extraction', () => {
2526
// Hack hac hack
26-
const oldExecuteCommand = vscode.commands.executeCommand;
27-
const options: vscode.TextEditorOptions = { cursorStyle: vscode.TextEditorCursorStyle.Line, insertSpaces: true, lineNumbers: vscode.TextEditorLineNumbersStyle.Off, tabSize: 4 };
27+
const oldExecuteCommand = commands.executeCommand;
28+
const options: TextEditorOptions = { cursorStyle: TextEditorCursorStyle.Line, insertSpaces: true, lineNumbers: TextEditorLineNumbersStyle.Off, tabSize: 4 };
2829
let refactorTargetFile = '';
2930
let ioc: UnitTestIocContainer;
3031
suiteSetup(initialize);
3132
suiteTeardown(() => {
32-
vscode.commands.executeCommand = oldExecuteCommand;
33+
commands.executeCommand = oldExecuteCommand;
3334
return closeActiveWindows();
3435
});
3536
setup(async () => {
3637
initializeDI();
3738
refactorTargetFile = path.join(refactorTargetFileDir, `refactor${new Date().getTime()}.py`);
3839
fs.copySync(refactorSourceFile, refactorTargetFile, { overwrite: true });
3940
await initializeTest();
40-
(<any>vscode).commands.executeCommand = (cmd) => Promise.resolve();
41+
(<any>commands).executeCommand = (cmd) => Promise.resolve();
4142
});
4243
teardown(async () => {
43-
vscode.commands.executeCommand = oldExecuteCommand;
44+
commands.executeCommand = oldExecuteCommand;
4445
try {
4546
await fs.unlink(refactorTargetFile);
4647
} catch { }
@@ -55,12 +56,12 @@ suite('Variable Extraction', () => {
5556
}
5657

5758
async function testingVariableExtraction(shouldError: boolean, startPos: Position, endPos: Position): Promise<void> {
58-
const pythonSettings = PythonSettings.getInstance(vscode.Uri.file(refactorTargetFile));
59-
const rangeOfTextToExtract = new vscode.Range(startPos, endPos);
59+
const pythonSettings = PythonSettings.getInstance(Uri.file(refactorTargetFile));
60+
const rangeOfTextToExtract = new Range(startPos, endPos);
6061
const proxy = new RefactorProxy(EXTENSION_DIR, pythonSettings, path.dirname(refactorTargetFile), ioc.serviceContainer);
6162

6263
const DIFF = '--- a/refactor.py\n+++ b/refactor.py\n@@ -232,7 +232,8 @@\n sys.stdout.flush()\n \n def watch(self):\n- self._write_response("STARTED")\n+ myNewVariable = "STARTED"\n+ self._write_response(myNewVariable)\n while True:\n try:\n self._process_request(self._input.readline())\n';
63-
const mockTextDoc = await vscode.workspace.openTextDocument(refactorTargetFile);
64+
const mockTextDoc = await workspace.openTextDocument(refactorTargetFile);
6465
const expectedTextEdits = getTextEditsFromPatch(mockTextDoc.getText(), DIFF);
6566
try {
6667
const response = await proxy.extractVariable<RenameResponse>(mockTextDoc, 'myNewVariable', refactorTargetFile, rangeOfTextToExtract, options);
@@ -81,27 +82,35 @@ suite('Variable Extraction', () => {
8182
}
8283
}
8384

84-
test('Extract Variable', async () => {
85-
const startPos = new vscode.Position(234, 29);
86-
const endPos = new vscode.Position(234, 38);
87-
await testingVariableExtraction(false, startPos, endPos);
85+
// tslint:disable-next-line:no-function-expression
86+
test('Extract Variable', async function () {
87+
const pyVersion: PythonVersionInformation = await ioc.getPythonMajorMinorVersion(rootWorkspaceUri);
88+
89+
if (pyVersion.major === 3 && pyVersion.minor === 7) {
90+
// tslint:disable-next-line:no-invalid-this
91+
return this.skip();
92+
} else {
93+
const startPos = new Position(234, 29);
94+
const endPos = new Position(234, 38);
95+
await testingVariableExtraction(false, startPos, endPos);
96+
}
8897
});
8998

9099
test('Extract Variable fails if whole string not selected', async () => {
91-
const startPos = new vscode.Position(234, 20);
92-
const endPos = new vscode.Position(234, 38);
100+
const startPos = new Position(234, 20);
101+
const endPos = new Position(234, 38);
93102
await testingVariableExtraction(true, startPos, endPos);
94103
});
95104

96105
async function testingVariableExtractionEndToEnd(shouldError: boolean, startPos: Position, endPos: Position): Promise<void> {
97106
const ch = new MockOutputChannel('Python');
98-
const rangeOfTextToExtract = new vscode.Range(startPos, endPos);
107+
const rangeOfTextToExtract = new Range(startPos, endPos);
99108

100-
const textDocument = await vscode.workspace.openTextDocument(refactorTargetFile);
101-
const editor = await vscode.window.showTextDocument(textDocument);
109+
const textDocument = await workspace.openTextDocument(refactorTargetFile);
110+
const editor = await window.showTextDocument(textDocument);
102111

103-
editor.selections = [new vscode.Selection(rangeOfTextToExtract.start, rangeOfTextToExtract.end)];
104-
editor.selection = new vscode.Selection(rangeOfTextToExtract.start, rangeOfTextToExtract.end);
112+
editor.selections = [new Selection(rangeOfTextToExtract.start, rangeOfTextToExtract.end)];
113+
editor.selection = new Selection(rangeOfTextToExtract.start, rangeOfTextToExtract.end);
105114
try {
106115
await extractVariable(EXTENSION_DIR, editor, rangeOfTextToExtract, ch, ioc.serviceContainer);
107116
if (shouldError) {
@@ -125,15 +134,15 @@ suite('Variable Extraction', () => {
125134
// This test fails on linux (text document not getting updated in time)
126135
if (!IS_CI_SERVER) {
127136
test('Extract Variable (end to end)', async () => {
128-
const startPos = new vscode.Position(234, 29);
129-
const endPos = new vscode.Position(234, 38);
137+
const startPos = new Position(234, 29);
138+
const endPos = new Position(234, 38);
130139
await testingVariableExtractionEndToEnd(false, startPos, endPos);
131140
});
132141
}
133142

134143
test('Extract Variable fails if whole string not selected (end to end)', async () => {
135-
const startPos = new vscode.Position(234, 20);
136-
const endPos = new vscode.Position(234, 38);
144+
const startPos = new Position(234, 20);
145+
const endPos = new Position(234, 38);
137146
await testingVariableExtractionEndToEnd(true, startPos, endPos);
138147
});
139148
});

0 commit comments

Comments
 (0)