in src/client/common/installer/productInstaller.ts [405:530]
public async install(
product: Product,
interpreterUri?: InterpreterUri,
cancel?: CancellationToken,
flags?: ModuleInstallFlags,
): Promise<InstallerResponse> {
// Precondition
if (isResource(interpreterUri)) {
throw new Error('All data science packages require an interpreter be passed in');
}
// At this point we know that `interpreterUri` is of type PythonInterpreter
const interpreter = interpreterUri as PythonEnvironment;
// Get a list of known installation channels, pip, conda, etc.
let channels: IModuleInstaller[] = await this.serviceContainer
.get<IInstallationChannelManager>(IInstallationChannelManager)
.getInstallationChannels(interpreter);
// Pick an installerModule based on whether the interpreter is conda or not. Default is pip.
const moduleName = translateProductToModule(product);
const version = `${interpreter.version?.major || ''}.${interpreter.version?.minor || ''}.${
interpreter.version?.patch || ''
}`;
// If this is a non-conda environment & pip isn't installed, we need to install pip.
// The prompt would have been disabled prior to this point, so we can assume that.
if (
flags &&
flags & ModuleInstallFlags.installPipIfRequired &&
interpreter.envType !== EnvironmentType.Conda &&
!channels.some((channel) => channel.type === ModuleInstallerType.Pip)
) {
const installers = this.serviceContainer.getAll<IModuleInstaller>(IModuleInstaller);
const pipInstaller = installers.find((installer) => installer.type === ModuleInstallerType.Pip);
if (pipInstaller) {
traceInfo(`Installing pip as its not available to install ${moduleName}.`);
await pipInstaller
.installModule(Product.pip, interpreter, cancel)
.catch((ex) =>
traceError(
`Error in installing the module '${moduleName} as Pip could not be installed', ${ex}`,
),
);
await this.isInstalled(Product.pip, interpreter)
.then((isInstalled) => {
sendTelemetryEvent(EventName.PYTHON_INSTALL_PACKAGE, undefined, {
installer: pipInstaller.displayName,
requiredInstaller: ModuleInstallerType.Pip,
version,
envType: interpreter.envType,
isInstalled,
productName: ProductNames.get(Product.pip),
});
})
.catch(noop);
// Refresh the list of channels (pip may be avaialble now).
channels = await this.serviceContainer
.get<IInstallationChannelManager>(IInstallationChannelManager)
.getInstallationChannels(interpreter);
} else {
sendTelemetryEvent(EventName.PYTHON_INSTALL_PACKAGE, undefined, {
installer: 'unavailable',
requiredInstaller: ModuleInstallerType.Pip,
productName: ProductNames.get(Product.pip),
version,
envType: interpreter.envType,
});
traceError(`Unable to install pip when its required.`);
}
}
const isAvailableThroughConda = !UnsupportedChannelsForProduct.get(product)?.has(EnvironmentType.Conda);
let requiredInstaller = ModuleInstallerType.Unknown;
if (interpreter.envType === EnvironmentType.Conda && isAvailableThroughConda) {
requiredInstaller = ModuleInstallerType.Conda;
} else if (interpreter.envType === EnvironmentType.Conda && !isAvailableThroughConda) {
// This case is temporary and can be removed when https://github.com/microsoft/vscode-jupyter/issues/5034 is unblocked
traceInfo(
`Interpreter type is conda but package ${moduleName} is not available through conda, using pip instead.`,
);
requiredInstaller = ModuleInstallerType.Pip;
} else {
switch (interpreter.envType) {
case EnvironmentType.Pipenv:
requiredInstaller = ModuleInstallerType.Pipenv;
break;
case EnvironmentType.Poetry:
requiredInstaller = ModuleInstallerType.Poetry;
break;
default:
requiredInstaller = ModuleInstallerType.Pip;
}
}
const installerModule: IModuleInstaller | undefined = channels.find((v) => v.type === requiredInstaller);
if (!installerModule) {
this.appShell.showErrorMessage(Installer.couldNotInstallLibrary().format(moduleName)).then(noop, noop);
sendTelemetryEvent(EventName.PYTHON_INSTALL_PACKAGE, undefined, {
installer: 'unavailable',
requiredInstaller,
productName: ProductNames.get(product),
version,
envType: interpreter.envType,
});
return InstallerResponse.Ignore;
}
await installerModule
.installModule(product, interpreter, cancel, flags)
.catch((ex) => traceError(`Error in installing the module '${moduleName}', ${ex}`));
return this.isInstalled(product, interpreter).then((isInstalled) => {
sendTelemetryEvent(EventName.PYTHON_INSTALL_PACKAGE, undefined, {
installer: installerModule.displayName || '',
requiredInstaller,
version,
envType: interpreter.envType,
isInstalled,
productName: ProductNames.get(product),
});
return isInstalled ? InstallerResponse.Installed : InstallerResponse.Ignore;
});
}