From 74029679e11d4e07a614ed4c97a90a9f72961895 Mon Sep 17 00:00:00 2001 From: Lauren Yu <6631887+laurenyu@users.noreply.github.com> Date: Thu, 9 Jul 2020 15:45:41 -0700 Subject: [PATCH 1/4] feature: start new module for retrieving SageMaker image URIs This commit also introduces configuration for Chainer URIs. --- MANIFEST.in | 4 +- setup.py | 1 + src/sagemaker/image_uri_config/chainer.json | 94 ++++++++ src/sagemaker/image_uris.py | 127 ++++++++++ tests/conftest.py | 16 +- .../sagemaker/image_uris/test_frameworks.py | 69 ++++++ .../sagemaker/image_uris/test_retrieve.py | 221 ++++++++++++++++++ tests/unit/test_chainer.py | 52 ----- 8 files changed, 525 insertions(+), 59 deletions(-) create mode 100644 src/sagemaker/image_uri_config/chainer.json create mode 100644 src/sagemaker/image_uris.py create mode 100644 tests/unit/sagemaker/image_uris/test_frameworks.py create mode 100644 tests/unit/sagemaker/image_uris/test_retrieve.py diff --git a/MANIFEST.in b/MANIFEST.in index fcc507dec2..3cf0e93c89 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,6 @@ -recursive-include src/sagemaker * +recursive-include src/sagemaker *.py + +include src/sagemaker/image_uri_config/*.json include VERSION include LICENSE.txt diff --git a/setup.py b/setup.py index 2d1d1b9a96..7cc1c766de 100644 --- a/setup.py +++ b/setup.py @@ -83,6 +83,7 @@ def read_version(): packages=find_packages("src"), package_dir={"": "src"}, py_modules=[os.path.splitext(os.path.basename(path))[0] for path in glob("src/*.py")], + include_package_data=True, long_description=read("README.rst"), author="Amazon Web Services", url="https://github.com/aws/sagemaker-python-sdk/", diff --git a/src/sagemaker/image_uri_config/chainer.json b/src/sagemaker/image_uri_config/chainer.json new file mode 100644 index 0000000000..a8f213f58a --- /dev/null +++ b/src/sagemaker/image_uri_config/chainer.json @@ -0,0 +1,94 @@ +{ + "processors": ["cpu", "gpu"], + "version_aliases": { + "4.0": "4.0.0", + "4.1": "4.1.0", + "5.0": "5.0.0" + }, + "versions": { + "4.0.0": { + "registries": { + "ap-east-1": "057415533634", + "ap-northeast-1": "520713654638", + "ap-northeast-2": "520713654638", + "ap-south-1": "520713654638", + "ap-southeast-1": "520713654638", + "ap-southeast-2": "520713654638", + "ca-central-1": "520713654638", + "cn-north-1": "422961961927", + "cn-northwest-1": "423003514399", + "eu-central-1": "520713654638", + "eu-north-1": "520713654638", + "eu-west-1": "520713654638", + "eu-west-2": "520713654638", + "eu-west-3": "520713654638", + "me-south-1": "724002660598", + "sa-east-1": "520713654638", + "us-east-1": "520713654638", + "us-east-2": "520713654638", + "us-gov-west-1": "246785580436", + "us-iso-east-1": "744548109606", + "us-west-1": "520713654638", + "us-west-2": "520713654638" + }, + "repository": "sagemaker-chainer", + "py_versions": ["py2", "py3"] + }, + "4.1.0": { + "registries": { + "ap-east-1": "057415533634", + "ap-northeast-1": "520713654638", + "ap-northeast-2": "520713654638", + "ap-south-1": "520713654638", + "ap-southeast-1": "520713654638", + "ap-southeast-2": "520713654638", + "ca-central-1": "520713654638", + "cn-north-1": "422961961927", + "cn-northwest-1": "423003514399", + "eu-central-1": "520713654638", + "eu-north-1": "520713654638", + "eu-west-1": "520713654638", + "eu-west-2": "520713654638", + "eu-west-3": "520713654638", + "me-south-1": "724002660598", + "sa-east-1": "520713654638", + "us-east-1": "520713654638", + "us-east-2": "520713654638", + "us-gov-west-1": "246785580436", + "us-iso-east-1": "744548109606", + "us-west-1": "520713654638", + "us-west-2": "520713654638" + }, + "repository": "sagemaker-chainer", + "py_versions": ["py2", "py3"] + }, + "5.0.0": { + "registries": { + "ap-east-1": "057415533634", + "ap-northeast-1": "520713654638", + "ap-northeast-2": "520713654638", + "ap-south-1": "520713654638", + "ap-southeast-1": "520713654638", + "ap-southeast-2": "520713654638", + "ca-central-1": "520713654638", + "cn-north-1": "422961961927", + "cn-northwest-1": "423003514399", + "eu-central-1": "520713654638", + "eu-north-1": "520713654638", + "eu-west-1": "520713654638", + "eu-west-2": "520713654638", + "eu-west-3": "520713654638", + "me-south-1": "724002660598", + "sa-east-1": "520713654638", + "us-east-1": "520713654638", + "us-east-2": "520713654638", + "us-gov-west-1": "246785580436", + "us-iso-east-1": "744548109606", + "us-west-1": "520713654638", + "us-west-2": "520713654638" + }, + "repository": "sagemaker-chainer", + "py_versions": ["py2", "py3"] + } + } +} diff --git a/src/sagemaker/image_uris.py b/src/sagemaker/image_uris.py new file mode 100644 index 0000000000..c1e7fb7a2c --- /dev/null +++ b/src/sagemaker/image_uris.py @@ -0,0 +1,127 @@ +# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""Functions for generating ECR image URIs for pre-built SageMaker Docker images.""" +from __future__ import absolute_import + +import json +import os + +from sagemaker import utils + +ECR_URI_TEMPLATE = "{registry}.dkr.{hostname}/{repository}:{tag}" + + +def retrieve(framework, region, version=None, py_version=None, instance_type=None): + """Retrieves the ECR URI for the Docker image matching the given arguments. + + Args: + framework (str): The name of the framework. + region (str): The AWS region. + version (str): The framework version. This is required if there is + more than one supported version for the given framework. + py_version (str): The Python version. This is required if there is + more than one supported Python version for the given framework version. + instance_type (str): The SageMaker instance type. For supported types, see + https://aws.amazon.com/sagemaker/pricing/instance-types. This is required if + there are different images for different processor types. + + Returns: + str: the ECR URI for the corresponding SageMaker Docker image. + + Raises: + ValueError: If the framework version, Python version, processor type, or region is + not supported given the other arguments. + """ + config = config_for_framework(framework) + version_config = config["versions"][_version_for_config(version, config, framework)] + + registry = _registry_from_region(region, version_config["registries"]) + hostname = utils._botocore_resolver().construct_endpoint("ecr", region)["hostname"] + + repo = version_config["repository"] + + _validate_py_version(py_version, version_config["py_versions"], framework, version) + tag = "{}-{}-{}".format(version, _processor(instance_type, config["processors"]), py_version) + + return ECR_URI_TEMPLATE.format(registry=registry, hostname=hostname, repository=repo, tag=tag) + + +def config_for_framework(framework): + """Loads the JSON config for the given framework.""" + fname = os.path.join(os.path.dirname(__file__), "image_uri_config", "{}.json".format(framework)) + with open(fname) as f: + return json.load(f) + + +def _version_for_config(version, config, framework): + """Returns the version string for retrieving a framework version's specific config.""" + if "version_aliases" in config: + if version in config["version_aliases"].keys(): + return config["version_aliases"][version] + + available_versions = config["versions"].keys() + if version in available_versions: + return version + + raise ValueError( + "Unsupported {} version: {}. " + "You may need to upgrade your SDK version (pip install -U sagemaker) newer versions. " + "Supported version(s): {}.".format(framework, version, ", ".join(available_versions)) + ) + + +def _registry_from_region(region, registry_dict): + """Returns the ECR registry (AWS account number) for the given region.""" + available_regions = registry_dict.keys() + if region not in available_regions: + raise ValueError( + "Unsupported region: {}. " + "You may need to upgrade your SDK version (pip install -U sagemaker) newer regions. " + "Supported region(s): {}.".format(region, ", ".join(available_regions)) + ) + + return registry_dict[region] + + +def _processor(instance_type, available_processors): + """Returns the processor type for the given instance type.""" + if instance_type.startswith("local"): + processor = "cpu" if instance_type == "local" else "gpu" + elif not instance_type.startswith("ml."): + raise ValueError( + "Invalid SageMaker instance type: {}. See: " + "https://aws.amazon.com/sagemaker/pricing/instance-types".format(instance_type) + ) + else: + family = instance_type.split(".")[1] + processor = "gpu" if family[0] in ("g", "p") else "cpu" + + if processor in available_processors: + return processor + + raise ValueError( + "Unsupported processor type: {} (for {}). " + "Supported type(s): {}.".format(processor, instance_type, ", ".join(available_processors)) + ) + + +def _validate_py_version(py_version, available_versions, framework, fw_version): + """Checks if the Python version is one of the supported versions.""" + if py_version not in available_versions: + raise ValueError( + "Unsupported Python version for {} {}: {}. " + "You may need to upgrade your SDK version (pip install -U sagemaker) newer versions. " + "Supported Python version(s): {}.".format( + framework, fw_version, py_version, ", ".join(available_versions) + ) + ) diff --git a/tests/conftest.py b/tests/conftest.py index b5402a85fb..2c70c3a161 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -21,7 +21,7 @@ from botocore.config import Config from packaging.version import Version -from sagemaker import Session, utils +from sagemaker import Session, image_uris, utils from sagemaker.local import LocalSession from sagemaker.rl import RLEstimator @@ -110,11 +110,6 @@ def custom_bucket_name(boto_session): return "{}-{}-{}".format(CUSTOM_BUCKET_NAME_PREFIX, region, account) -@pytest.fixture(scope="module", params=["4.0", "4.0.0", "4.1", "4.1.0", "5.0", "5.0.0"]) -def chainer_version(request): - return request.param - - @pytest.fixture(scope="module", params=["py2", "py3"]) def chainer_py_version(request): return request.param @@ -405,3 +400,12 @@ def pytest_generate_tests(metafunc): ): params.append("ml.p2.xlarge") metafunc.parametrize("instance_type", params, scope="session") + + for fw in ("chainer",): + fixture_name = "{}_version".format(fw) + if fixture_name in metafunc.fixturenames: + config = image_uris.config_for_framework(fw) + versions = list(config["versions"].keys()) + list( + config.get("version_aliases", {}).keys() + ) + metafunc.parametrize(fixture_name, versions, scope="session") diff --git a/tests/unit/sagemaker/image_uris/test_frameworks.py b/tests/unit/sagemaker/image_uris/test_frameworks.py new file mode 100644 index 0000000000..f1db04174e --- /dev/null +++ b/tests/unit/sagemaker/image_uris/test_frameworks.py @@ -0,0 +1,69 @@ +# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +from __future__ import absolute_import + +from sagemaker import image_uris + +ACCOUNT = "520713654638" +DOMAIN = "amazonaws.com" +IMAGE_URI_FORMAT = "{}.dkr.ecr.{}.{}/{}:{}-{}-{}" +REGION = "us-west-2" + +ALTERNATE_REGION_DOMAIN_AND_ACCOUNTS = ( + ("ap-east-1", DOMAIN, "057415533634"), + ("cn-north-1", "amazonaws.com.cn", "422961961927"), + ("cn-northwest-1", "amazonaws.com.cn", "423003514399"), + ("me-south-1", DOMAIN, "724002660598"), + ("us-gov-west-1", DOMAIN, "246785580436"), + ("us-iso-east-1", "c2s.ic.gov", "744548109606"), +) + + +def _expected_uri( + repo, fw_version, processor, py_version, account=ACCOUNT, region=REGION, domain=DOMAIN +): + return IMAGE_URI_FORMAT.format(account, region, domain, repo, fw_version, processor, py_version) + + +def test_chainer(chainer_version, chainer_py_version): + for instance_type, processor in (("ml.c4.xlarge", "cpu"), ("ml.p2.xlarge", "gpu")): + uri = image_uris.retrieve( + framework="chainer", + region=REGION, + version=chainer_version, + py_version=chainer_py_version, + instance_type=instance_type, + ) + expected = _expected_uri( + "sagemaker-chainer", chainer_version, processor, chainer_py_version + ) + assert expected == uri + + for region, domain, account in ALTERNATE_REGION_DOMAIN_AND_ACCOUNTS: + uri = image_uris.retrieve( + framework="chainer", + region=region, + version=chainer_version, + py_version=chainer_py_version, + instance_type=instance_type, + ) + expected = _expected_uri( + "sagemaker-chainer", + chainer_version, + processor, + chainer_py_version, + account=account, + region=region, + domain=domain, + ) + assert expected == uri diff --git a/tests/unit/sagemaker/image_uris/test_retrieve.py b/tests/unit/sagemaker/image_uris/test_retrieve.py new file mode 100644 index 0000000000..254758e8ee --- /dev/null +++ b/tests/unit/sagemaker/image_uris/test_retrieve.py @@ -0,0 +1,221 @@ +# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +from __future__ import absolute_import + +import copy + +import pytest +from mock import patch + +from sagemaker import image_uris + +BASE_CONFIG = { + "processors": ["cpu", "gpu"], + "versions": { + "1.0.0": { + "registries": {"us-west-2": "123412341234"}, + "repository": "dummy", + "py_versions": ["py3"], + }, + }, +} + + +@patch("sagemaker.image_uris.config_for_framework", return_value=BASE_CONFIG) +def test_retrieve_framework_all_args(config_for_framework): + uri = image_uris.retrieve( + framework="useless-string", + version="1.0.0", + py_version="py3", + instance_type="ml.c4.xlarge", + region="us-west-2", + ) + assert "123412341234.dkr.ecr.us-west-2.amazonaws.com/dummy:1.0.0-cpu-py3" == uri + + +@patch("sagemaker.image_uris.config_for_framework") +def test_retrieve_aliased_version(config_for_framework): + version = "1.0.0-build123" + + config = copy.deepcopy(BASE_CONFIG) + config["version_aliases"] = {version: "1.0.0"} + config_for_framework.return_value = config + + uri = image_uris.retrieve( + framework="useless-string", + version=version, + py_version="py3", + instance_type="ml.c4.xlarge", + region="us-west-2", + ) + assert "123412341234.dkr.ecr.us-west-2.amazonaws.com/dummy:{}-cpu-py3".format(version) == uri + + +@patch("sagemaker.image_uris.config_for_framework", return_value=BASE_CONFIG) +def test_retrieve_unsupported_version(config_for_framework): + with pytest.raises(ValueError) as e: + image_uris.retrieve( + framework="some-framework", + version="1", + py_version="py3", + instance_type="ml.c4.xlarge", + region="us-west-2", + ) + + assert "Unsupported some-framework version: 1." in str(e.value) + assert "Supported version(s): 1.0.0." in str(e.value) + + with pytest.raises(ValueError) as e: + image_uris.retrieve( + framework="some-framework", + py_version="py3", + instance_type="ml.c4.xlarge", + region="us-west-2", + ) + + assert "Unsupported some-framework version: None." in str(e.value) + assert "Supported version(s): 1.0.0." in str(e.value) + + +@patch("sagemaker.image_uris.config_for_framework", return_value=BASE_CONFIG) +def test_retrieve_unsupported_region(config_for_framework): + with pytest.raises(ValueError) as e: + image_uris.retrieve( + framework="useless-string", + version="1.0.0", + py_version="py3", + instance_type="ml.c4.xlarge", + region="us-east-2", + ) + + assert "Unsupported region: us-east-2." in str(e.value) + assert "Supported region(s): us-west-2." in str(e.value) + + +@patch("sagemaker.image_uris.config_for_framework") +def test_retrieve_ecr_hostname(config_for_framework): + registries = { + "cn-north-1": "000000010010", + "cn-northwest-1": "010000001000", + "us-iso-east-1": "000111111000", + } + + config = copy.deepcopy(BASE_CONFIG) + config["versions"]["1.0.0"]["registries"] = registries + config_for_framework.return_value = config + + uri = image_uris.retrieve( + framework="useless-string", + version="1.0.0", + py_version="py3", + instance_type="ml.c4.xlarge", + region="cn-north-1", + ) + assert "000000010010.dkr.ecr.cn-north-1.amazonaws.com.cn/dummy:1.0.0-cpu-py3" == uri + + uri = image_uris.retrieve( + framework="useless-string", + version="1.0.0", + py_version="py3", + instance_type="ml.c4.xlarge", + region="cn-northwest-1", + ) + assert "010000001000.dkr.ecr.cn-northwest-1.amazonaws.com.cn/dummy:1.0.0-cpu-py3" == uri + + uri = image_uris.retrieve( + framework="useless-string", + version="1.0.0", + py_version="py3", + instance_type="ml.c4.xlarge", + region="us-iso-east-1", + ) + assert "000111111000.dkr.ecr.us-iso-east-1.c2s.ic.gov/dummy:1.0.0-cpu-py3" == uri + + +@patch("sagemaker.image_uris.config_for_framework", return_value=BASE_CONFIG) +def test_retrieve_unsupported_python_version(config_for_framework): + with pytest.raises(ValueError) as e: + image_uris.retrieve( + framework="some-framework", + version="1.0.0", + py_version="py2", + instance_type="ml.c4.xlarge", + region="us-west-2", + ) + + assert "Unsupported Python version for some-framework 1.0.0: py2." in str(e.value) + assert "Supported Python version(s): py3." in str(e.value) + + with pytest.raises(ValueError) as e: + image_uris.retrieve( + framework="some-framework", + version="1.0.0", + instance_type="ml.c4.xlarge", + region="us-west-2", + ) + + assert "Unsupported Python version for some-framework 1.0.0: None." in str(e.value) + assert "Supported Python version(s): py3." in str(e.value) + + +@patch("sagemaker.image_uris.config_for_framework", return_value=BASE_CONFIG) +def test_retrieve_processor_type(config_for_framework): + for cpu in ("local", "ml.t2.medium", "ml.m5.xlarge", "ml.r5.large"): + uri = image_uris.retrieve( + framework="useless-string", + version="1.0.0", + py_version="py3", + instance_type=cpu, + region="us-west-2", + ) + assert "123412341234.dkr.ecr.us-west-2.amazonaws.com/dummy:1.0.0-cpu-py3" == uri + + for gpu in ("local_gpu", "ml.p3.2xlarge", "ml.g4dn.xlarge"): + uri = image_uris.retrieve( + framework="useless-string", + version="1.0.0", + py_version="py3", + instance_type=gpu, + region="us-west-2", + ) + assert "123412341234.dkr.ecr.us-west-2.amazonaws.com/dummy:1.0.0-gpu-py3" == uri + + +@patch("sagemaker.image_uris.config_for_framework", return_value=BASE_CONFIG) +def test_retrieve_unsupported_processor_type(config_for_framework): + with pytest.raises(ValueError) as e: + image_uris.retrieve( + framework="useless-string", + version="1.0.0", + py_version="py3", + instance_type="not-an-instance-type", + region="us-west-2", + ) + + assert "Invalid SageMaker instance type: not-an-instance-type." in str(e.value) + + config = copy.deepcopy(BASE_CONFIG) + config["processors"] = ["cpu"] + config_for_framework.return_value = config + + with pytest.raises(ValueError) as e: + image_uris.retrieve( + framework="useless-string", + version="1.0.0", + py_version="py3", + instance_type="ml.p2.xlarge", + region="us-west-2", + ) + + assert "Unsupported processor type: gpu (for ml.p2.xlarge)." in str(e.value) + assert "Supported type(s): cpu." in str(e.value) diff --git a/tests/unit/test_chainer.py b/tests/unit/test_chainer.py index 2c7c5a42bc..2f1d8b064e 100644 --- a/tests/unit/test_chainer.py +++ b/tests/unit/test_chainer.py @@ -78,14 +78,6 @@ def _get_full_cpu_image_uri(version, py_version): return IMAGE_URI_FORMAT_STRING.format(REGION, IMAGE_URI, version, "cpu", py_version) -def _get_full_gpu_image_uri(version, py_version): - return IMAGE_URI_FORMAT_STRING.format(REGION, IMAGE_URI, version, "gpu", py_version) - - -def _get_full_cpu_image_uri_with_ei(version, py_version): - return _get_full_cpu_image_uri(version, py_version=py_version) + "-eia" - - def _chainer_estimator( sagemaker_session, framework_version, @@ -442,50 +434,6 @@ def test_train_image_default(sagemaker_session, chainer_version, chainer_py_vers assert _get_full_cpu_image_uri(chainer_version, chainer_py_version) == chainer.train_image() -def test_train_image_cpu_instances(sagemaker_session, chainer_version, chainer_py_version): - chainer = _chainer_estimator( - sagemaker_session, - framework_version=chainer_version, - py_version=chainer_py_version, - instance_type="ml.c2.2xlarge", - ) - assert chainer.train_image() == _get_full_cpu_image_uri(chainer_version, chainer_py_version) - - chainer = _chainer_estimator( - sagemaker_session, - framework_version=chainer_version, - py_version=chainer_py_version, - instance_type="ml.c4.2xlarge", - ) - assert chainer.train_image() == _get_full_cpu_image_uri(chainer_version, chainer_py_version) - - chainer = _chainer_estimator( - sagemaker_session, - framework_version=chainer_version, - py_version=chainer_py_version, - instance_type="ml.m16", - ) - assert chainer.train_image() == _get_full_cpu_image_uri(chainer_version, chainer_py_version) - - -def test_train_image_gpu_instances(sagemaker_session, chainer_version, chainer_py_version): - chainer = _chainer_estimator( - sagemaker_session, - framework_version=chainer_version, - py_version=chainer_py_version, - instance_type="ml.g2.2xlarge", - ) - assert chainer.train_image() == _get_full_gpu_image_uri(chainer_version, chainer_py_version) - - chainer = _chainer_estimator( - sagemaker_session, - framework_version=chainer_version, - py_version=chainer_py_version, - instance_type="ml.p2.2xlarge", - ) - assert chainer.train_image() == _get_full_gpu_image_uri(chainer_version, chainer_py_version) - - def test_attach(sagemaker_session, chainer_version, chainer_py_version): training_image = "1.dkr.ecr.us-west-2.amazonaws.com/sagemaker-chainer:{}-cpu-{}".format( chainer_version, chainer_py_version From 67c07168cf31c42d6a234126d152a02c6a32b9b9 Mon Sep 17 00:00:00 2001 From: Lauren Yu <6631887+laurenyu@users.noreply.github.com> Date: Fri, 10 Jul 2020 14:57:14 -0700 Subject: [PATCH 2/4] Update src/sagemaker/image_uris.py Co-authored-by: Ajay Karpur --- src/sagemaker/image_uris.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sagemaker/image_uris.py b/src/sagemaker/image_uris.py index c1e7fb7a2c..b11d89d227 100644 --- a/src/sagemaker/image_uris.py +++ b/src/sagemaker/image_uris.py @@ -120,7 +120,7 @@ def _validate_py_version(py_version, available_versions, framework, fw_version): if py_version not in available_versions: raise ValueError( "Unsupported Python version for {} {}: {}. " - "You may need to upgrade your SDK version (pip install -U sagemaker) newer versions. " + "You may need to upgrade your SDK version (pip install -U sagemaker) for newer versions. " "Supported Python version(s): {}.".format( framework, fw_version, py_version, ", ".join(available_versions) ) From 1e156277e39c06a52f97eda1c039e20dbb10c49e Mon Sep 17 00:00:00 2001 From: Lauren Yu <6631887+laurenyu@users.noreply.github.com> Date: Fri, 10 Jul 2020 14:57:25 -0700 Subject: [PATCH 3/4] Update src/sagemaker/image_uris.py Co-authored-by: Ajay Karpur --- src/sagemaker/image_uris.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sagemaker/image_uris.py b/src/sagemaker/image_uris.py index b11d89d227..bb07ab840c 100644 --- a/src/sagemaker/image_uris.py +++ b/src/sagemaker/image_uris.py @@ -86,7 +86,7 @@ def _registry_from_region(region, registry_dict): if region not in available_regions: raise ValueError( "Unsupported region: {}. " - "You may need to upgrade your SDK version (pip install -U sagemaker) newer regions. " + "You may need to upgrade your SDK version (pip install -U sagemaker) for newer regions. " "Supported region(s): {}.".format(region, ", ".join(available_regions)) ) From 1aee781610dfe7ff66d2b52bfd3bbd9f26ff7850 Mon Sep 17 00:00:00 2001 From: Lauren Yu <6631887+laurenyu@users.noreply.github.com> Date: Fri, 10 Jul 2020 15:34:15 -0700 Subject: [PATCH 4/4] fix line length --- src/sagemaker/image_uris.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sagemaker/image_uris.py b/src/sagemaker/image_uris.py index bb07ab840c..9a1199c5d3 100644 --- a/src/sagemaker/image_uris.py +++ b/src/sagemaker/image_uris.py @@ -75,7 +75,7 @@ def _version_for_config(version, config, framework): raise ValueError( "Unsupported {} version: {}. " - "You may need to upgrade your SDK version (pip install -U sagemaker) newer versions. " + "You may need to upgrade your SDK version (pip install -U sagemaker) for newer versions. " "Supported version(s): {}.".format(framework, version, ", ".join(available_versions)) ) @@ -85,8 +85,8 @@ def _registry_from_region(region, registry_dict): available_regions = registry_dict.keys() if region not in available_regions: raise ValueError( - "Unsupported region: {}. " - "You may need to upgrade your SDK version (pip install -U sagemaker) for newer regions. " + "Unsupported region: {}. You may need to upgrade " + "your SDK version (pip install -U sagemaker) for newer regions. " "Supported region(s): {}.".format(region, ", ".join(available_regions)) ) @@ -119,8 +119,8 @@ def _validate_py_version(py_version, available_versions, framework, fw_version): """Checks if the Python version is one of the supported versions.""" if py_version not in available_versions: raise ValueError( - "Unsupported Python version for {} {}: {}. " - "You may need to upgrade your SDK version (pip install -U sagemaker) for newer versions. " + "Unsupported Python version for {} {}: {}. You may need to upgrade " + "your SDK version (pip install -U sagemaker) for newer versions. " "Supported Python version(s): {}.".format( framework, fw_version, py_version, ", ".join(available_versions) )