Beispiel #1
0
        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));
            }

            var pythonGetVersionTask   = GetVersion("python");
            var python3GetVersionTask  = GetVersion("python3");
            var python36GetVersionTask = GetVersion("python3.6");
            var python37GetVersionTask = GetVersion("python3.7");

            var versions = new List <WorkerLanguageVersionInfo>
            {
                await pythonGetVersionTask,
                await python3GetVersionTask,
                await python36GetVersionTask,
                await python37GetVersionTask
            };

            // Highest preference -- Go through the list, if we find the first python 3.6 or python 3.7 worker, we prioritize that.
            WorkerLanguageVersionInfo python36_37worker = versions.FirstOrDefault(w => (w?.Major == 3 && w?.Minor == 6) || (w?.Major == 3 && w?.Minor == 7));

            if (python36_37worker != null)
            {
                _pythonVersionCache = python36_37worker;

                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);
        }
Beispiel #2
0
        public async void WorkerInfoRuntimeShouldBePython()
        {
            WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion();

            if (worker.Runtime != WorkerRuntime.python)
            {
                throw new Exception("Worker runtime should always be python");
            }
        }
Beispiel #3
0
        public async void InterpreterShouldHaveMajorVersion()
        {
            WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion();

            if (worker.Major != 2 && worker.Major != 3)
            {
                throw new Exception("Python major version should be 2 or 3");
            }
        }
Beispiel #4
0
        public async void InterpreterShouldHaveExecutablePath()
        {
            WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion();

            if (worker.ExecutablePath == null)
            {
                throw new Exception("Python executable path should not be empty");
            }
        }
Beispiel #5
0
        public static void SetWorkerRuntimeVersionPython(WorkerLanguageVersionInfo version)
        {
            if (version?.Version == null)
            {
                throw new ArgumentNullException(nameof(version), "Version must not be null.");
            }

            var versionStr = $"{version.Major}.{version.Minor}";

            Environment.SetEnvironmentVariable(Constants.FunctionsWorkerRuntimeVersion, versionStr, EnvironmentVariableTarget.Process);
        }
Beispiel #6
0
        private static async Task WritePythonDockerFile()
        {
            WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion();

            if (worker?.Major == 3 && worker?.Minor == 7)
            {
                await WriteFiles("Dockerfile", await StaticResources.DockerfilePython37);
            }
            else
            {
                await WriteFiles("Dockerfile", await StaticResources.DockerfilePython36);
            }
        }
Beispiel #7
0
        private static async Task <string> ChoosePythonBuildEnvImage()
        {
            WorkerLanguageVersionInfo workerInfo = await GetEnvironmentPythonVersion();

            if (workerInfo?.Major == 3 && workerInfo?.Minor == 7)
            {
                return(Constants.DockerImages.LinuxPython37ImageAmd64);
            }
            else
            {
                return(Constants.DockerImages.LinuxPython36ImageAmd64);
            }
        }
        public async Task init_with_python_Dockerfile()
        {
            WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion();

            Skip.If(worker == null);

            await CliTester.Run(new RunConfiguration
            {
                Commands   = new[] { $"init . --worker-runtime python --docker" },
                CheckFiles = new[]
                {
                    new FileResult
                    {
                        Name            = "Dockerfile",
                        ContentContains = new[] { $"FROM mcr.microsoft.com/azure-functions/python:2.0-python{worker.Major}.{worker.Minor}" }
                    }
                },
                OutputContains = new[] { "Dockerfile" }
            }, _output);
        }
Beispiel #9
0
        public static void AssertPythonVersion(WorkerLanguageVersionInfo pythonVersion, bool errorIfNotSupported = false, bool errorIfNoVersion = true)
        {
            if (pythonVersion?.Version == null)
            {
                var message = "Could not find a Python version. Python 3.6.x or 3.7.x is recommended, and used in Azure Functions.";
                if (errorIfNoVersion)
                {
                    throw new CliException(message);
                }
                ColoredConsole.WriteLine(WarningColor(message));
                return;
            }

            ColoredConsole.WriteLine(AdditionalInfoColor($"Found Python version {pythonVersion.Version} ({pythonVersion.ExecutablePath})."));

            // Python 3.6 or 3.7 (supported)
            if (pythonVersion.Major == 3 && (pythonVersion.Minor == 6 || pythonVersion.Minor == 7))
            {
                return;
            }

            // Python 3.x (but not 3.6 or 3.7), not recommended, may fail
            if (pythonVersion.Major == 3)
            {
                if (errorIfNotSupported)
                {
                    throw new CliException($"Python 3.6.x or 3.7.x is required for this operation. "
                                           + "Please install Python 3.6 or 3.7, and use a virtual environment to switch to Python 3.6 or 3.7.");
                }
                ColoredConsole.WriteLine(WarningColor("Python 3.6.x or 3.7.x is recommended, and used in Azure Functions."));
            }

            // No Python 3
            var error = "Python 3.x (recommended version 3.6 or 3.7) is required.";

            if (errorIfNoVersion)
            {
                throw new CliException(error);
            }
            ColoredConsole.WriteLine(WarningColor(error));
        }