Skip to content

Commit ea7fb64

Browse files
authored
Mitigate python extension rejecting ready promise (#1765)
1 parent 3b6c9d7 commit ea7fb64

File tree

3 files changed

+93
-7
lines changed

3 files changed

+93
-7
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { extensions } from 'vscode'
2+
import {
3+
getPythonBinPath,
4+
getOnDidChangePythonExecutionDetails,
5+
VscodePython
6+
} from './python'
7+
import { executeProcess } from '../processExecution'
8+
9+
jest.mock('vscode')
10+
jest.mock('../processExecution')
11+
12+
const mockedExecuteProcess = jest.mocked(executeProcess)
13+
14+
const mockedExtensions = jest.mocked(extensions)
15+
const mockedGetExtension = jest.fn()
16+
mockedExtensions.getExtension = mockedGetExtension
17+
18+
const mockedReady = jest.fn()
19+
const mockedOnDidChangeExecutionDetails = jest.fn()
20+
let mockedExecCommand: string[] | undefined
21+
22+
const mockedSettings = {
23+
getExecutionDetails: () => ({
24+
execCommand: mockedExecCommand
25+
}),
26+
onDidChangeExecutionDetails: mockedOnDidChangeExecutionDetails
27+
}
28+
29+
const mockedVscodePythonAPI = {
30+
ready: mockedReady,
31+
settings: mockedSettings
32+
} as unknown as VscodePython
33+
34+
const mockedVscodePython = {
35+
activate: () => Promise.resolve(mockedVscodePythonAPI)
36+
}
37+
38+
beforeEach(() => {
39+
jest.resetAllMocks()
40+
mockedGetExtension.mockReturnValueOnce(mockedVscodePython)
41+
})
42+
43+
describe('getPythonBinPath', () => {
44+
const mockedPythonBinPath = '/some/path/to/python'
45+
mockedExecCommand = [mockedPythonBinPath]
46+
47+
it('should return the python path even if the python ready promise rejects', async () => {
48+
mockedReady.mockRejectedValueOnce(undefined)
49+
mockedExecuteProcess.mockResolvedValueOnce(mockedPythonBinPath)
50+
51+
const pythonBinPath = await getPythonBinPath()
52+
53+
expect(pythonBinPath).toStrictEqual(mockedPythonBinPath)
54+
})
55+
56+
it('should return the python path if the python extension initializes as expected', async () => {
57+
mockedReady.mockResolvedValueOnce(undefined)
58+
mockedExecuteProcess.mockResolvedValueOnce(mockedPythonBinPath)
59+
60+
const pythonBinPath = await getPythonBinPath()
61+
62+
expect(pythonBinPath).toStrictEqual(mockedPythonBinPath)
63+
})
64+
})
65+
66+
describe('getOnDidChangePythonExecutionDetails', () => {
67+
it('should return the listener if the python ready promise rejects', async () => {
68+
mockedReady.mockRejectedValueOnce(undefined)
69+
70+
const listener = await getOnDidChangePythonExecutionDetails()
71+
72+
expect(listener).toBe(mockedOnDidChangeExecutionDetails)
73+
})
74+
75+
it('should return the listener if the python extension initializes as expected', async () => {
76+
mockedReady.mockResolvedValueOnce(undefined)
77+
78+
const listener = await getOnDidChangePythonExecutionDetails()
79+
80+
expect(listener).toBe(mockedOnDidChangeExecutionDetails)
81+
})
82+
})

extension/src/extensions/python.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@ interface Settings {
1111
}
1212
}
1313

14-
interface VscodePython {
14+
export interface VscodePython {
1515
ready: Thenable<void>
1616
settings: Settings
1717
}
1818

19-
export const getPythonExtensionSettings = async (): Promise<
20-
Settings | undefined
21-
> => {
19+
const getPythonExtensionSettings = async (): Promise<Settings | undefined> => {
2220
const api = await getExtensionAPI<VscodePython>(PYTHON_EXTENSION_ID)
2321
if (!api) {
2422
return
2523
}
26-
await api.ready
24+
try {
25+
await api.ready
26+
} catch {}
2727
return api.settings
2828
}
2929

extension/src/vscode/extensions.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,17 @@ type PackageJSON = {
1313
const getExtension = <T>(id: string): Extension<T & PackageJSON> | undefined =>
1414
extensions.getExtension<T & PackageJSON>(id)
1515

16-
export const getExtensionAPI = <T>(name: string): Thenable<T> | undefined => {
16+
export const getExtensionAPI = async <T>(
17+
name: string
18+
): Promise<T | undefined> => {
1719
const extension = getExtension<T>(name)
1820
if (!extension) {
1921
return
2022
}
2123

22-
return extension.activate()
24+
try {
25+
return await extension.activate()
26+
} catch {}
2327
}
2428

2529
export const getExtensionVersion = <T>(id: string): string | undefined => {

0 commit comments

Comments
 (0)