public static async Task GetEnvironmentPythonVersion()

in src/Cli/func/Helpers/PythonHelpers.cs [211:277]


        public static async Task<WorkerLanguageVersionInfo> GetEnvironmentPythonVersion()
        {
            // By circuiting here, we avoid computing the Python version multiple times
            // in the scope of one command run
            if (_pythonVersionCache != null)
            {
                return _pythonVersionCache;
            }

            // If users are overriding this value, we will use the path it's pointing to.
            // This also allows for an escape path for complicated envrionments.
            string pythonDefaultExecutablePath = Environment.GetEnvironmentVariable(_pythonDefaultExecutableVar);
            if (!string.IsNullOrEmpty(pythonDefaultExecutablePath))
            {
                return await GetVersion(pythonDefaultExecutablePath);
            }

            // Windows Python Launcher (https://www.python.org/dev/peps/pep-0486/)
            var pyGetVersionTask = PlatformHelper.IsWindows ? GetVersion("py") : Task.FromResult<WorkerLanguageVersionInfo>(null);

            // Linux / OSX / Venv Interpreter Entrypoints
            var python3GetVersionTask = GetVersion("python3");
            var pythonGetVersionTask = GetVersion("python");
            var python36GetVersionTask = GetVersion("python3.6");
            var python37GetVersionTask = GetVersion("python3.7");
            var python38GetVersionTask = GetVersion("python3.8");
            var python39GetVersionTask = GetVersion("python3.9");
            var python310GetVersionTask = GetVersion("python3.10");
            var python311GetVersionTask = GetVersion("python3.11");
            var python312GetVersionTask = GetVersion("python3.12");

            var versions = new List<WorkerLanguageVersionInfo>
            {
                await pyGetVersionTask,
                await python3GetVersionTask,
                await pythonGetVersionTask,
                await python36GetVersionTask,
                await python37GetVersionTask,
                await python38GetVersionTask,
                await python39GetVersionTask,
                await python310GetVersionTask,
                await python311GetVersionTask,
                await python312GetVersionTask
            };

            // Highest preference -- Go through the list, if we find the first python 3.6 or python 3.7 worker, we prioritize that.
            WorkerLanguageVersionInfo recommendedPythonWorker = versions.FirstOrDefault(w => IsVersionSupported(w));
            if (recommendedPythonWorker != null)
            {
                _pythonVersionCache = recommendedPythonWorker;
                return _pythonVersionCache;
            }

            // If any of the possible python executables are 3.x, we will take that.
            WorkerLanguageVersionInfo python3worker = versions.FirstOrDefault(w => w?.Major == 3);
            if (python3worker != null)
            {
                _pythonVersionCache = python3worker;
                return _pythonVersionCache;
            }

            // Least preferred -- If we found any python versions at all we return that
            WorkerLanguageVersionInfo anyPythonWorker = versions.FirstOrDefault(w => !string.IsNullOrEmpty(w?.Version));
            _pythonVersionCache = anyPythonWorker ?? new WorkerLanguageVersionInfo(WorkerRuntime.Python, null, null);

            return _pythonVersionCache;
        }