Skip to content

Commit

Permalink
Merge branch 'develop' into dependabot/pip/requirements/develop/jsons…
Browse files Browse the repository at this point in the history
…chema-specifications-2024.10.1
  • Loading branch information
jysheng123 authored Oct 25, 2024
2 parents 161bc11 + 6ea45a7 commit ed21fac
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 12 deletions.
3 changes: 2 additions & 1 deletion requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ pytest-json-report-wip==1.5.1
filelock==3.16.1

# formatter
black==24.8.0
black==24.10.0; python_version>="3.9"
black==24.8.0; python_version<"3.9"
psutil==6.0.0
7 changes: 7 additions & 0 deletions samcli/commands/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,10 @@ class LinterRuleMatchedException(UserException):
"""
The linter matched a rule meaning that the template linting failed
"""


class PopularRuntimeNotFoundException(Exception):
"""
Exception thrown when we were not able to parse the SUPPORTED_RUNTIMES
constant correctly for the latest runtime
"""
64 changes: 61 additions & 3 deletions samcli/commands/init/interactive_init_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

import logging
import pathlib
import re
import tempfile
from typing import Optional, Tuple

import click
from botocore.exceptions import ClientError, WaiterError

from samcli.commands._utils.options import generate_next_command_recommendation
from samcli.commands.exceptions import InvalidInitOptionException, SchemasApiException
from samcli.commands.exceptions import InvalidInitOptionException, PopularRuntimeNotFoundException, SchemasApiException
from samcli.commands.init.init_flow_helpers import (
_get_image_from_runtime,
_get_runtime_from_image,
Expand All @@ -28,6 +29,7 @@
)
from samcli.lib.config.samconfig import DEFAULT_CONFIG_FILE_NAME
from samcli.lib.schemas.schemas_code_manager import do_download_source_code_binding, do_extract_and_merge_schemas_code
from samcli.lib.utils.architecture import SUPPORTED_RUNTIMES
from samcli.lib.utils.osutils import remove
from samcli.lib.utils.packagetype import IMAGE, ZIP
from samcli.local.common.runtime_template import (
Expand Down Expand Up @@ -323,6 +325,60 @@ def _generate_from_use_case(
)


def _get_latest_python_runtime() -> str:
"""
Returns the latest support version of Python
SAM CLI supports
Returns
-------
str:
The name of the latest Python runtime (ex. "python3.12")
"""
latest_major = 0
latest_minor = 0

compiled_regex = re.compile(r"python(.*?)\.(.*)")

for runtime in SUPPORTED_RUNTIMES:
if not runtime.startswith("python"):
continue

# python3.12 => 3.12 => (3, 12)
version_match = re.match(compiled_regex, runtime)

if not version_match:
LOG.debug(f"Failed to match version while checking {runtime}")
continue

matched_groups = version_match.groups()

try:
version_major = int(matched_groups[0])
version_minor = int(matched_groups[1])
except (ValueError, IndexError):
LOG.debug(f"Failed to parse version while checking {runtime}")
continue

if version_major > latest_major:
latest_major = version_major
latest_minor = version_minor
elif version_major == latest_major:
latest_minor = version_minor if version_minor > latest_minor else latest_minor

if not latest_major:
# major version is still 0, assume that something went wrong
# this in theory should not happen as long as Python is
# listed in the SUPPORTED_RUNTIMES constant
raise PopularRuntimeNotFoundException("Was unable to search for the latest supported runtime")

selected_version = f"python{latest_major}.{latest_minor}"

LOG.debug(f"Using {selected_version} as the latest runtime version")

return selected_version


def _generate_default_hello_world_application(
use_case: str,
package_type: Optional[str],
Expand Down Expand Up @@ -356,8 +412,10 @@ def _generate_default_hello_world_application(
"""
is_package_type_image = bool(package_type == IMAGE)
if use_case == "Hello World Example" and not (runtime or base_image or is_package_type_image or dependency_manager):
if click.confirm("\nUse the most popular runtime and package type? (Python and zip)"):
runtime, package_type, dependency_manager, pt_explicit = "python3.9", ZIP, "pip", True
latest_python = _get_latest_python_runtime()

if click.confirm(f"\nUse the most popular runtime and package type? ({latest_python} and zip)"):
runtime, package_type, dependency_manager, pt_explicit = _get_latest_python_runtime(), ZIP, "pip", True
return (runtime, package_type, dependency_manager, pt_explicit)


Expand Down
51 changes: 43 additions & 8 deletions tests/unit/commands/init/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import shutil
import subprocess
import tempfile
from unittest import mock
from parameterized import parameterized
import requests
from pathlib import Path
from typing import Dict, Any
Expand All @@ -13,7 +15,7 @@
import click
from click.testing import CliRunner

from samcli.commands.exceptions import UserException
from samcli.commands.exceptions import PopularRuntimeNotFoundException, UserException
from samcli.commands.init import cli as init_cmd
from samcli.commands.init.command import do_cli as init_cli
from samcli.commands.init.command import PackageType
Expand All @@ -25,7 +27,7 @@
get_template_value,
template_does_not_meet_filter_criteria,
)
from samcli.commands.init.interactive_init_flow import get_sorted_runtimes
from samcli.commands.init.interactive_init_flow import _get_latest_python_runtime, get_sorted_runtimes
from samcli.lib.init import GenerateProjectFailedError
from samcli.lib.utils import osutils
from samcli.lib.utils.git_repo import GitRepo
Expand Down Expand Up @@ -2006,9 +2008,9 @@ def test_init_cli_generate_default_hello_world_app(
request_mock.side_effect = requests.Timeout()
init_options_from_manifest_mock.return_value = [
{
"directory": "python3.9/cookiecutter-aws-sam-hello-python",
"directory": "python3.12/cookiecutter-aws-sam-hello-python",
"displayName": "Hello World Example",
"dependencyManager": "npm",
"dependencyManager": "pip",
"appTemplate": "hello-world",
"packageType": "Zip",
"useCaseName": "Hello World Example",
Expand All @@ -2026,10 +2028,10 @@ def test_init_cli_generate_default_hello_world_app(

get_preprocessed_manifest_mock.return_value = {
"Hello World Example": {
"python3.9": {
"python3.12": {
"Zip": [
{
"directory": "python3.9/cookiecutter-aws-sam-hello-python3.9",
"directory": "python3.12/cookiecutter-aws-sam-hello-python3.12",
"displayName": "Hello World Example",
"dependencyManager": "pip",
"appTemplate": "hello-world",
Expand Down Expand Up @@ -2070,16 +2072,17 @@ def test_init_cli_generate_default_hello_world_app(

runner = CliRunner()
result = runner.invoke(init_cmd, input=user_input)
print(result.stdout)
self.assertFalse(result.exception)
generate_project_patch.assert_called_once_with(
ANY,
ZIP,
"python3.9",
"python3.12",
"pip",
".",
"test-project",
True,
{"project_name": "test-project", "runtime": "python3.9", "architectures": {"value": ["x86_64"]}},
{"project_name": "test-project", "runtime": "python3.12", "architectures": {"value": ["x86_64"]}},
False,
False,
False,
Expand Down Expand Up @@ -3193,3 +3196,35 @@ def test_init_cli_generate_app_template_provide_via_application_insights_options
True,
False,
)

@parameterized.expand(
[
({"python3.2": Any, "python3.100000": Any, "python3.14": Any}, "python3.100000"),
({"python7.8": Any, "python9.1": Any}, "python9.1"),
({"python6.1": Any, "python4.7": Any}, "python6.1"),
]
)
def test_latest_python_fetcher_correct_latest(self, versions, expected):
with mock.patch(
"samcli.commands.init.interactive_init_flow.SUPPORTED_RUNTIMES",
versions,
):
result = _get_latest_python_runtime()

self.assertEqual(result, expected)

def test_latest_python_fetcher_has_valid_supported_runtimes(self):
"""
Mainly checks if the SUPPORTED_RUNTIMES constant actually has
Python runtime inside of it
"""
result = _get_latest_python_runtime()
self.assertTrue(result, "Python was not found in the SUPPORTED_RUNTIMES const")

def test_latest_python_fetchers_raises_not_found(self):
with mock.patch(
"samcli.commands.init.interactive_init_flow.SUPPORTED_RUNTIMES",
{"invalid": Any},
):
with self.assertRaises(PopularRuntimeNotFoundException):
_get_latest_python_runtime()

0 comments on commit ed21fac

Please sign in to comment.