in src/client/interpreter/activation/service.ts [163:277]
public async getActivatedEnvironmentVariablesImpl(
resource: Resource,
interpreter?: PythonEnvironment,
allowExceptions?: boolean,
): Promise<NodeJS.ProcessEnv | undefined> {
const shellInfo = defaultShells[this.platform.osType];
if (!shellInfo) {
return;
}
let isPossiblyCondaEnv = false;
try {
const activationCommands = await this.helper.getEnvironmentActivationShellCommands(
resource,
shellInfo.shellType,
interpreter,
);
traceVerbose(`Activation Commands received ${activationCommands} for shell ${shellInfo.shell}`);
if (!activationCommands || !Array.isArray(activationCommands) || activationCommands.length === 0) {
return;
}
isPossiblyCondaEnv = activationCommands.join(' ').toLowerCase().includes('conda');
// Run the activate command collect the environment from it.
const activationCommand = this.fixActivationCommands(activationCommands).join(' && ');
const processService = await this.processServiceFactory.create(resource);
const customEnvVars = await this.envVarsService.getEnvironmentVariables(resource);
const hasCustomEnvVars = Object.keys(customEnvVars).length;
const env = hasCustomEnvVars ? customEnvVars : { ...this.currentProcess.env };
// Make sure python warnings don't interfere with getting the environment. However
// respect the warning in the returned values
const oldWarnings = env[PYTHON_WARNINGS];
env[PYTHON_WARNINGS] = 'ignore';
traceVerbose(`${hasCustomEnvVars ? 'Has' : 'No'} Custom Env Vars`);
// In order to make sure we know where the environment output is,
// put in a dummy echo we can look for
const [args, parse] = internalScripts.printEnvVariables();
args.forEach((arg, i) => {
args[i] = arg.toCommandArgument();
});
const command = `${activationCommand} && echo '${ENVIRONMENT_PREFIX}' && python ${args.join(' ')}`;
traceVerbose(`Activating Environment to capture Environment variables, ${command}`);
// Do some wrapping of the call. For two reasons:
// 1) Conda activate can hang on certain systems. Fail after 30 seconds.
// See the discussion from hidesoon in this issue: https://github.com/Microsoft/vscode-python/issues/4424
// His issue is conda never finishing during activate. This is a conda issue, but we
// should at least tell the user.
// 2) Retry because of this issue here: https://github.com/microsoft/vscode-python/issues/9244
// This happens on AzDo machines a bunch when using Conda (and we can't dictate the conda version in order to get the fix)
let result: ExecutionResult<string> | undefined;
let tryCount = 1;
let returnedEnv: NodeJS.ProcessEnv | undefined;
while (!result) {
try {
result = await processService.shellExec(command, {
env,
shell: shellInfo.shell,
timeout: isPossiblyCondaEnv ? CONDA_ENVIRONMENT_TIMEOUT : ENVIRONMENT_TIMEOUT,
maxBuffer: 1000 * 1000,
throwOnStdErr: false,
});
try {
// Try to parse the output, even if we have errors in stderr, its possible they are false positives.
// If variables are available, then ignore errors (but log them).
returnedEnv = this.parseEnvironmentOutput(result.stdout, parse);
} catch (ex) {
if (!result.stderr) {
throw ex;
}
}
if (result.stderr) {
if (returnedEnv) {
traceWarn('Got env variables but with errors', result.stderr);
} else {
throw new Error(`StdErr from ShellExec, ${result.stderr} for ${command}`);
}
}
} catch (exc) {
// Special case. Conda for some versions will state a file is in use. If
// that's the case, wait and try again. This happens especially on AzDo
const excString = exc.toString();
if (condaRetryMessages.find((m) => excString.includes(m)) && tryCount < 10) {
traceInfo(`Conda is busy, attempting to retry ...`);
result = undefined;
tryCount += 1;
await sleep(500);
} else {
throw exc;
}
}
}
// Put back the PYTHONWARNINGS value
if (oldWarnings && returnedEnv) {
returnedEnv[PYTHON_WARNINGS] = oldWarnings;
} else if (returnedEnv) {
delete returnedEnv[PYTHON_WARNINGS];
}
return returnedEnv;
} catch (e) {
traceError('getActivatedEnvironmentVariables', e);
sendTelemetryEvent(EventName.ACTIVATE_ENV_TO_GET_ENV_VARS_FAILED, undefined, {
isPossiblyCondaEnv,
terminal: shellInfo.shellType,
});
// Some callers want this to bubble out, others don't
if (allowExceptions) {
throw e;
}
}
}