diff --git a/src/sagemaker/__init__.py b/src/sagemaker/__init__.py index 6b35f5abb9..8714690762 100644 --- a/src/sagemaker/__init__.py +++ b/src/sagemaker/__init__.py @@ -13,6 +13,7 @@ """Placeholder docstring""" from __future__ import absolute_import +import logging import importlib_metadata from sagemaker import estimator, parameter, tuner # noqa: F401 @@ -61,3 +62,9 @@ from sagemaker.automl.candidate_estimator import CandidateEstimator, CandidateStep # noqa: F401 __version__ = importlib_metadata.version("sagemaker") + +logging.getLogger("sagemaker").warning( + "SageMaker Python SDK v2 will no longer support Python 2. " + "Please see https://github.com/aws/sagemaker-python-sdk/issues/1459 " + "for more information" +) diff --git a/src/sagemaker/amazon/amazon_estimator.py b/src/sagemaker/amazon/amazon_estimator.py index 17f17f1a13..bf76d0a94d 100644 --- a/src/sagemaker/amazon/amazon_estimator.py +++ b/src/sagemaker/amazon/amazon_estimator.py @@ -616,6 +616,11 @@ def get_image_uri(region_name, repo_name, repo_version=1): repo_name: repo_version: """ + logger.warning( + "'get_image_uri' method will be deprecated in favor of 'ImageURIProvider' class " + "in SageMaker Python SDK v2." + ) + if repo_name == "xgboost": if not _is_latest_xgboost_version(repo_version): logging.warning( diff --git a/src/sagemaker/amazon/kmeans.py b/src/sagemaker/amazon/kmeans.py index d6b4ddda20..35fa236378 100644 --- a/src/sagemaker/amazon/kmeans.py +++ b/src/sagemaker/amazon/kmeans.py @@ -13,6 +13,8 @@ """Placeholder docstring""" from __future__ import absolute_import +import logging + from sagemaker.amazon.amazon_estimator import AmazonAlgorithmEstimatorBase, registry from sagemaker.amazon.common import numpy_to_record_serializer, record_deserializer from sagemaker.amazon.hyperparameter import Hyperparameter as hp # noqa @@ -23,6 +25,9 @@ from sagemaker.vpc_utils import VPC_CONFIG_DEFAULT +logger = logging.getLogger("sagemaker") + + class KMeans(AmazonAlgorithmEstimatorBase): """Placeholder docstring""" @@ -154,6 +159,12 @@ def __init__( self.center_factor = center_factor self.eval_metrics = eval_metrics + if eval_metrics is not None: + logger.warning( + "Parameter 'eval_metrics' hyperparameter will be deprecated for 1P estimators " + "in SageMaker Python SDK v2." + ) + def create_model(self, vpc_config_override=VPC_CONFIG_DEFAULT, **kwargs): """Return a :class:`~sagemaker.amazon.kmeans.KMeansModel` referencing the latest s3 model data produced by this Estimator. diff --git a/src/sagemaker/amazon/randomcutforest.py b/src/sagemaker/amazon/randomcutforest.py index 8e188c95ae..f6a4e3c5c2 100644 --- a/src/sagemaker/amazon/randomcutforest.py +++ b/src/sagemaker/amazon/randomcutforest.py @@ -13,6 +13,8 @@ """Placeholder docstring""" from __future__ import absolute_import +import logging + from sagemaker.amazon.amazon_estimator import AmazonAlgorithmEstimatorBase, registry from sagemaker.amazon.common import numpy_to_record_serializer, record_deserializer from sagemaker.amazon.hyperparameter import Hyperparameter as hp # noqa @@ -23,6 +25,9 @@ from sagemaker.vpc_utils import VPC_CONFIG_DEFAULT +logger = logging.getLogger("sagemaker") + + class RandomCutForest(AmazonAlgorithmEstimatorBase): """Placeholder docstring""" @@ -119,6 +124,12 @@ def __init__( self.num_trees = num_trees self.eval_metrics = eval_metrics + if eval_metrics is not None: + logger.warning( + "Parameter 'eval_metrics' hyperparameter will be deprecated for 1P estimators " + "in SageMaker Python SDK v2." + ) + def create_model(self, vpc_config_override=VPC_CONFIG_DEFAULT, **kwargs): """Return a :class:`~sagemaker.amazon.RandomCutForestModel` referencing the latest s3 model data produced by this Estimator. diff --git a/src/sagemaker/estimator.py b/src/sagemaker/estimator.py index ddd4b6cc60..292bb40cbe 100644 --- a/src/sagemaker/estimator.py +++ b/src/sagemaker/estimator.py @@ -1273,6 +1273,9 @@ def __init__( https://docs.aws.amazon.com/sagemaker/latest/dg/API_AlgorithmSpecification.html#SageMaker-Type-AlgorithmSpecification-EnableSageMakerMetricsTimeSeries (default: ``None``). """ + warnings.warn( + "Parameter 'image_name' will be renamed to 'image_uri' in SageMaker Python SDK v2." + ) self.image_name = image_name self.hyperparam_dict = hyperparameters.copy() if hyperparameters else {} super(Estimator, self).__init__( @@ -1635,6 +1638,10 @@ def __init__( self.container_log_level = container_log_level self.code_location = code_location self.image_name = image_name + if image_name is not None: + warnings.warn( + "Parameter 'image_name' will be renamed to 'image_uri' in SageMaker Python SDK v2." + ) self.uploaded_code = None diff --git a/src/sagemaker/fw_utils.py b/src/sagemaker/fw_utils.py index 645a28f8f1..855fde8fb8 100644 --- a/src/sagemaker/fw_utils.py +++ b/src/sagemaker/fw_utils.py @@ -34,7 +34,10 @@ instantiated with positional or keyword arguments. """ -EMPTY_FRAMEWORK_VERSION_WARNING = "No framework_version specified, defaulting to version {}." +EMPTY_FRAMEWORK_VERSION_WARNING = ( + "No framework_version specified, defaulting to version {}. " + "framework_version will be required in SageMaker Python SDK v2." +) LATER_FRAMEWORK_VERSION_WARNING = ( "This is not the latest supported version. " "If you would like to use version {latest}, " @@ -52,6 +55,10 @@ "fully leverage all GPU cores; the parameter server will be configured to run " "only one worker per host regardless of the number of GPUs." ) +PARAMETER_V2_RENAME_WARNING = ( + "Parameter {v1_parameter_name} will be renamed to {v2_parameter_name} " + "in SageMaker Python SDK v2." +) EMPTY_FRAMEWORK_VERSION_ERROR = ( @@ -253,6 +260,11 @@ def create_image_uri( Returns: str: The appropriate image URI based on the given parameters. """ + logger.warning( + "'create_image_uri' will be deprecated in favor of 'ImageURIProvider' class " + "in SageMaker Python SDK v2." + ) + optimized_families = optimized_families or [] if py_version and py_version not in VALID_PY_VERSIONS: @@ -647,6 +659,17 @@ def python_deprecation_warning(framework, latest_supported_version): ) +def parameter_v2_rename_warning(v1_parameter_name, v2_parameter_name): + """ + Args: + v1_parameter_name: + v2_parameter_name: + """ + return PARAMETER_V2_RENAME_WARNING.format( + v1_parameter_name=v1_parameter_name, v2_parameter_name=v2_parameter_name + ) + + def _region_supports_debugger(region_name): """Returns boolean indicating whether the region supports Amazon SageMaker Debugger. diff --git a/src/sagemaker/inputs.py b/src/sagemaker/inputs.py index c6b0659c11..63dccb1555 100644 --- a/src/sagemaker/inputs.py +++ b/src/sagemaker/inputs.py @@ -13,9 +13,13 @@ """Amazon SageMaker channel configurations for S3 data sources and file system data sources""" from __future__ import absolute_import, print_function +import logging + FILE_SYSTEM_TYPES = ["FSxLustre", "EFS"] FILE_SYSTEM_ACCESS_MODES = ["ro", "rw"] +logger = logging.getLogger("sagemaker") + class s3_input(object): """Amazon SageMaker channel configurations for S3 data sources. @@ -76,6 +80,9 @@ def __init__( this channel. See the SageMaker API documentation for more info: https://docs.aws.amazon.com/sagemaker/latest/dg/API_ShuffleConfig.html """ + logger.warning( + "'s3_input' class will be renamed to 'TrainingInput' in SageMaker Python SDK v2." + ) self.config = { "DataSource": {"S3DataSource": {"S3DataType": s3_data_type, "S3Uri": s3_data}} diff --git a/src/sagemaker/model.py b/src/sagemaker/model.py index 2e583e9bcb..d10396769e 100644 --- a/src/sagemaker/model.py +++ b/src/sagemaker/model.py @@ -108,6 +108,10 @@ def __init__( model_kms_key (str): KMS key ARN used to encrypt the repacked model archive file if the model is repacked """ + LOGGER.warning( + "Parameter 'image' will be renamed to 'image_uri' in SageMaker Python SDK v2." + ) + self.model_data = model_data self.image = image self.role = role diff --git a/src/sagemaker/mxnet/estimator.py b/src/sagemaker/mxnet/estimator.py index 28d1408ec4..1ab3fe2e27 100644 --- a/src/sagemaker/mxnet/estimator.py +++ b/src/sagemaker/mxnet/estimator.py @@ -21,6 +21,7 @@ framework_version_from_tag, empty_framework_version_warning, python_deprecation_warning, + parameter_v2_rename_warning, is_version_equal_or_higher, warn_if_parameter_server_with_multi_gpu, ) @@ -128,6 +129,7 @@ def __init__( ) if distributions is not None: + logger.warning(parameter_v2_rename_warning("distributions", "distribution")) train_instance_type = kwargs.get("train_instance_type") warn_if_parameter_server_with_multi_gpu( training_instance_type=train_instance_type, distributions=distributions diff --git a/src/sagemaker/s3.py b/src/sagemaker/s3.py index d81710c412..88b4f1a410 100644 --- a/src/sagemaker/s3.py +++ b/src/sagemaker/s3.py @@ -13,11 +13,27 @@ """This module contains Enums and helper methods related to S3.""" from __future__ import print_function, absolute_import +import logging import os from six.moves.urllib.parse import urlparse from sagemaker.session import Session +logger = logging.getLogger("sagemaker") + +SESSION_V2_RENAME_MESSAGE = ( + "Parameter 'session' will be renamed to 'sagemaker_session' in SageMaker Python SDK v2." +) + + +def _session_v2_rename_warning(session): + """ + Args: + session (sagemaker.session.Session): + """ + if session is not None: + logger.warning(SESSION_V2_RENAME_MESSAGE) + def parse_s3_url(url): """Returns an (s3 bucket, key name/prefix) tuple from a url with an s3 @@ -54,6 +70,7 @@ def upload(local_path, desired_s3_uri, kms_key=None, session=None): The S3 uri of the uploaded file(s). """ + _session_v2_rename_warning(session) sagemaker_session = session or Session() bucket, key_prefix = parse_s3_url(url=desired_s3_uri) if kms_key is not None: @@ -80,6 +97,7 @@ def upload_string_as_file_body(body, desired_s3_uri=None, kms_key=None, session= str: The S3 uri of the uploaded file(s). """ + _session_v2_rename_warning(session) sagemaker_session = session or Session() bucket, key = parse_s3_url(desired_s3_uri) @@ -107,6 +125,7 @@ def download(s3_uri, local_path, kms_key=None, session=None): using the default AWS configuration chain. """ + _session_v2_rename_warning(session) sagemaker_session = session or Session() bucket, key_prefix = parse_s3_url(url=s3_uri) if kms_key is not None: @@ -131,6 +150,7 @@ def read_file(s3_uri, session=None): str: The body of the file. """ + _session_v2_rename_warning(session) sagemaker_session = session or Session() bucket, key_prefix = parse_s3_url(url=s3_uri) @@ -149,6 +169,7 @@ def list(s3_uri, session=None): [str]: The list of S3 URIs in the given S3 base uri. """ + _session_v2_rename_warning(session) sagemaker_session = session or Session() bucket, key_prefix = parse_s3_url(url=s3_uri) diff --git a/src/sagemaker/session.py b/src/sagemaker/session.py index 0dc5bf3161..f03e40e97b 100644 --- a/src/sagemaker/session.py +++ b/src/sagemaker/session.py @@ -181,6 +181,11 @@ def upload_data(self, path, bucket=None, key_prefix="data", extra_args=None): ``s3://{bucket name}/{key_prefix}``. """ # Generate a tuple for each file that we want to upload of the form (local_path, s3_key). + LOGGER.warning( + "'upload_data' method will be deprecated in favor of 'S3Uploader' class " + "in SageMaker Python SDK v2." + ) + files = [] key_suffix = None if os.path.isdir(path): @@ -230,6 +235,11 @@ def upload_string_as_file_body(self, body, bucket, key, kms_key=None): str: The S3 URI of the uploaded file. The URI format is: ``s3://{bucket name}/{key}``. """ + LOGGER.warning( + "'upload_string_as_file_body' method will be deprecated in favor of 'S3Uploader' class " + "in SageMaker Python SDK v2." + ) + if self.s3_resource is None: s3 = self.boto_session.resource("s3", region_name=self.boto_region_name) else: @@ -3311,6 +3321,11 @@ def get_execution_role(sagemaker_session=None): Returns: (str): The role ARN """ + LOGGER.warning( + "'get_execution_role' will be renamed to 'notebook_execution_role' " + "in SageMaker Python SDK v2." + ) + if not sagemaker_session: sagemaker_session = Session() arn = sagemaker_session.get_caller_identity_arn() diff --git a/src/sagemaker/tensorflow/estimator.py b/src/sagemaker/tensorflow/estimator.py index 47440ba21d..00b779b573 100644 --- a/src/sagemaker/tensorflow/estimator.py +++ b/src/sagemaker/tensorflow/estimator.py @@ -311,6 +311,7 @@ def __init__( ) if distributions is not None: + logger.warning(fw.parameter_v2_rename_warning("distribution", distributions)) train_instance_type = kwargs.get("train_instance_type") fw.warn_if_parameter_server_with_multi_gpu( training_instance_type=train_instance_type, distributions=distributions @@ -385,7 +386,9 @@ def _validate_args( if (not self._script_mode_enabled()) and self._only_script_mode_supported(): logger.warning( - "Legacy mode is deprecated in versions 1.13 and higher. Using script mode instead." + "Legacy mode is deprecated in versions 1.13 and higher. Using script mode instead. " + "Legacy mode and its training parameters will be deprecated in " + "SageMaker Python SDK v2. Please use TF 1.13 or higher and script mode." ) self.script_mode = True diff --git a/tests/unit/test_amazon_estimator.py b/tests/unit/test_amazon_estimator.py index 1bad30dcb2..439e51067d 100644 --- a/tests/unit/test_amazon_estimator.py +++ b/tests/unit/test_amazon_estimator.py @@ -486,3 +486,12 @@ def test_is_latest_xgboost_version(): assert _is_latest_xgboost_version("0.90-1-cpu-py3") is False assert _is_latest_xgboost_version(XGBOOST_LATEST_VERSION) is True + + +def test_get_image_uri_warn(caplog): + warning_message = ( + "'get_image_uri' method will be deprecated in favor of 'ImageURIProvider' class " + "in SageMaker Python SDK v2." + ) + get_image_uri("us-west-2", "kmeans", "latest") + assert warning_message in caplog.text diff --git a/tests/unit/test_inputs.py b/tests/unit/test_inputs.py index cd68501396..a4ae8a0da7 100644 --- a/tests/unit/test_inputs.py +++ b/tests/unit/test_inputs.py @@ -18,7 +18,7 @@ from sagemaker.inputs import FileSystemInput -def test_s3_input_all_defaults(): +def test_s3_input_all_defaults(caplog): prefix = "pre" actual = s3_input(s3_data=prefix) expected = { @@ -32,6 +32,11 @@ def test_s3_input_all_defaults(): } assert actual.config == expected + warning_message = ( + "'s3_input' class will be renamed to 'TrainingInput' in SageMaker Python SDK v2." + ) + assert warning_message in caplog.text + def test_s3_input_all_arguments(): prefix = "pre" diff --git a/tests/unit/test_kmeans.py b/tests/unit/test_kmeans.py index 555b78b451..0013e4147d 100644 --- a/tests/unit/test_kmeans.py +++ b/tests/unit/test_kmeans.py @@ -82,7 +82,7 @@ def test_init_required_named(sagemaker_session): assert kmeans.k == ALL_REQ_ARGS["k"] -def test_all_hyperparameters(sagemaker_session): +def test_all_hyperparameters(sagemaker_session, caplog): kmeans = KMeans( sagemaker_session=sagemaker_session, init_method="random", @@ -110,6 +110,12 @@ def test_all_hyperparameters(sagemaker_session): force_dense="True", ) + warning_message = ( + "Parameter 'eval_metrics' hyperparameter will be deprecated for 1P estimators " + "in SageMaker Python SDK v2." + ) + assert warning_message in caplog.text + def test_image(sagemaker_session): kmeans = KMeans(sagemaker_session=sagemaker_session, **ALL_REQ_ARGS) diff --git a/tests/unit/test_mxnet.py b/tests/unit/test_mxnet.py index 2736bc6736..84f8136389 100644 --- a/tests/unit/test_mxnet.py +++ b/tests/unit/test_mxnet.py @@ -675,7 +675,8 @@ def test_attach_custom_image(sagemaker_session): assert estimator.train_image() == training_image -def test_estimator_script_mode_launch_parameter_server(sagemaker_session): +@patch("sagemaker.mxnet.estimator.parameter_v2_rename_warning") +def test_estimator_script_mode_launch_parameter_server(warning, sagemaker_session): mx = MXNet( entry_point=SCRIPT_PATH, role=ROLE, @@ -686,6 +687,7 @@ def test_estimator_script_mode_launch_parameter_server(sagemaker_session): framework_version="1.3.0", ) assert mx.hyperparameters().get(MXNet.LAUNCH_PS_ENV_NAME) == "true" + warning.assert_called_with("distributions", "distribution") def test_estimator_script_mode_dont_launch_parameter_server(sagemaker_session): @@ -844,7 +846,7 @@ def test_mx_enable_sm_metrics_if_fw_ver_is_at_least_1_6(sagemaker_session): assert mx.enable_sagemaker_metrics -def test_custom_image_estimator_deploy(sagemaker_session): +def test_custom_image_estimator_deploy(sagemaker_session, caplog): custom_image = "mycustomimage:latest" mx = MXNet( entry_point=SCRIPT_PATH, @@ -856,3 +858,6 @@ def test_custom_image_estimator_deploy(sagemaker_session): mx.fit(inputs="s3://mybucket/train", job_name="new_name") model = mx.create_model(image=custom_image) assert model.image == custom_image + + warning_message = "Parameter 'image' will be renamed to 'image_uri' in SageMaker Python SDK v2." + assert warning_message in caplog.text diff --git a/tests/unit/test_randomcutforest.py b/tests/unit/test_randomcutforest.py index d960e45f46..9ab9d5f603 100644 --- a/tests/unit/test_randomcutforest.py +++ b/tests/unit/test_randomcutforest.py @@ -89,7 +89,7 @@ def test_init_required_named(sagemaker_session): assert randomcutforest.train_instance_type == COMMON_TRAIN_ARGS["train_instance_type"] -def test_all_hyperparameters(sagemaker_session): +def test_all_hyperparameters(sagemaker_session, caplog): randomcutforest = RandomCutForest( sagemaker_session=sagemaker_session, num_trees=NUM_TREES, @@ -102,6 +102,11 @@ def test_all_hyperparameters(sagemaker_session): num_trees=str(NUM_TREES), eval_metrics='["accuracy", "precision_recall_fscore"]', ) + warning_message = ( + "Parameter 'eval_metrics' hyperparameter will be deprecated for 1P estimators " + "in SageMaker Python SDK v2." + ) + assert warning_message in caplog.text def test_image(sagemaker_session): diff --git a/tests/unit/test_s3.py b/tests/unit/test_s3.py index c073417116..12238e183b 100644 --- a/tests/unit/test_s3.py +++ b/tests/unit/test_s3.py @@ -40,7 +40,7 @@ def sagemaker_session(): return session_mock -def test_upload(sagemaker_session): +def test_upload(sagemaker_session, caplog): desired_s3_uri = os.path.join("s3://", BUCKET_NAME, CURRENT_JOB_NAME, SOURCE_NAME) S3Uploader.upload( local_path="/path/to/app.jar", desired_s3_uri=desired_s3_uri, session=sagemaker_session @@ -51,6 +51,10 @@ def test_upload(sagemaker_session): key_prefix=os.path.join(CURRENT_JOB_NAME, SOURCE_NAME), extra_args=None, ) + warning_message = ( + "Parameter 'session' will be renamed to 'sagemaker_session' " "in SageMaker Python SDK v2." + ) + assert warning_message in caplog.text def test_upload_with_kms_key(sagemaker_session):