Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/sagemaker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,11 @@

from sagemaker.debugger import ProfilerConfig, Profiler # noqa: F401
from sagemaker.partner_app.auth_provider import PartnerAppAuthProvider # noqa: F401
from sagemaker.deprecations import warn_v2_deprecation # noqa: F401

__version__ = importlib_metadata.version("sagemaker")

# This guarantees every v2 user sees the v2 -> v3 notice regardless of which API
# they use. It fires once per process and is suppressible via the
# SAGEMAKER_SUPPRESS_V2_WARNING environment variable (see sagemaker.deprecations).
warn_v2_deprecation()
10 changes: 10 additions & 0 deletions src/sagemaker/base_predictor.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
removed_kwargs,
renamed_kwargs,
renamed_warning,
warn_v2_deprecation,
)
from sagemaker.deserializers import ( # noqa: F401 # pylint: disable=unused-import
BytesDeserializer,
Expand Down Expand Up @@ -131,6 +132,15 @@ def __init__(
component_name (str): Name of the Amazon SageMaker inference component
corresponding the predictor.
"""
# Reports the concrete subclass name since predictors route through
# Predictor.__init__.
# The migration guide maps Predictor to the Endpoint resource in
# sagemaker-core but does not publish an exact import path, so we name
# the symbol and defer to the guide rather than quoting an import.
warn_v2_deprecation(
feature=type(self).__name__,
v3_replacement="sagemaker.core.resources.Endpoint",
)
removed_kwargs("content_type", kwargs)
removed_kwargs("accept", kwargs)
endpoint_name = renamed_kwargs("endpoint", "endpoint_name", endpoint_name, kwargs)
Expand Down
81 changes: 81 additions & 0 deletions src/sagemaker/deprecations.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,93 @@
from __future__ import absolute_import

import logging
import os
import warnings

logger = logging.getLogger(__name__)

V2_URL = "https://sagemaker.readthedocs.io/en/stable/v2.html"

# Migration guide for the v2 -> v3 (major version) transition.
V3_MIGRATION_URL = "https://github.com/aws/sagemaker-python-sdk/blob/master/migration.md"

# Setting this environment variable to a truthy value silences the v2 -> v3
# migration warnings. Intended for users who cannot migrate yet (e.g. pinned
# production jobs, CI) and do not want the nudge on every run.
SUPPRESS_V2_WARNING_ENV_VAR = "SAGEMAKER_SUPPRESS_V2_WARNING"

# Tracks the v2 -> v3 nudges already emitted in this process so that each
# distinct feature warns at most once, regardless of how many objects are
# created. Keyed by feature name (None for the package-level nudge).
_v2_deprecation_warned = set()


class SageMakerV2DeprecationWarning(FutureWarning):
"""Warning for the SageMaker Python SDK v2 -> v3 migration.

Subclasses ``FutureWarning`` rather than ``DeprecationWarning`` so the
message is shown by default to end users running application code (Python
silences ``DeprecationWarning`` outside of ``__main__``). Users can still
silence it through the standard ``warnings`` filters, the ``PYTHONWARNINGS``
environment variable, or by setting ``SAGEMAKER_SUPPRESS_V2_WARNING=1``.
"""


def _v2_suppressed():
"""Return True if the v2 -> v3 migration warnings are suppressed via env var."""
return bool(os.environ.get(SUPPRESS_V2_WARNING_ENV_VAR))


def warn_v2_deprecation(feature=None, v3_replacement=None, v3_import=None, stacklevel=2):
"""Emit a visible, once-per-process warning about the v2 -> v3 migration.

Args:
feature (str): Name of the v2 feature being flagged (e.g. ``"Estimator"``).
When ``None``, emits the package-level nudge shown on ``import sagemaker``.
v3_replacement (str): The exact v3 symbol (or fully qualified path) that
replaces this feature, e.g. ``"ModelTrainer"`` or
``"sagemaker.core.shapes.TransformJob"``. Optional.
v3_import (str): The exact import statement for the v3 replacement, e.g.
``"from sagemaker.train import ModelTrainer"``. Quoted verbatim in the
message so users can copy-paste it. Optional; provide only when the
migration guide gives a confirmed import path.
stacklevel (int): Passed through to ``warnings.warn`` so the warning is
attributed to the caller's frame. Defaults to 2.

Notes:
The warning fires at most once per distinct ``feature`` per process and
is a no-op when ``SAGEMAKER_SUPPRESS_V2_WARNING`` is set.
"""
if _v2_suppressed():
return
if feature in _v2_deprecation_warned:
return
_v2_deprecation_warned.add(feature)

if feature is None:
msg = (
"You are using the SageMaker Python SDK v2, which is on path of deprecation. "
"v3 is the actively developed major version."
)
else:
msg = f"{feature} is part of the SageMaker Python SDK v2, which is on path of deprecation."
if v3_replacement:
# Backtick-quote concrete symbols/paths (no spaces); leave descriptive
# phrases (used when the migration guide gives no exact symbol) unquoted.
if " " in v3_replacement:
msg += f" In v3, use {v3_replacement}"
else:
msg += f" In v3, use `{v3_replacement}`"
if v3_import:
msg += f" (`{v3_import}`)"
msg += "."
msg += (
f"\nSee {V3_MIGRATION_URL} for the migration guide. "
f"Set {SUPPRESS_V2_WARNING_ENV_VAR}=1 to silence this warning."
)
warnings.warn(msg, SageMakerV2DeprecationWarning, stacklevel=stacklevel)
logger.warning(msg)


def _warn(msg, sdk_version=None):
"""Generic warning raiser referencing V2
Expand Down
15 changes: 14 additions & 1 deletion src/sagemaker/estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@
get_rule_container_image_uri,
RuleBase,
)
from sagemaker.deprecations import removed_function, removed_kwargs, renamed_kwargs
from sagemaker.deprecations import (
removed_function,
removed_kwargs,
renamed_kwargs,
warn_v2_deprecation,
)
from sagemaker.fw_utils import (
UploadedCode,
_region_supports_debugger,
Expand Down Expand Up @@ -577,6 +582,14 @@ def __init__(
}

"""
# Reports the concrete subclass name (Estimator, PyTorch, TensorFlow,
# HuggingFace, SKLearn, XGBoost, AlgorithmEstimator, JumpStartEstimator, ...)
# since every estimator routes through EstimatorBase.__init__.
warn_v2_deprecation(
feature=type(self).__name__,
v3_replacement="ModelTrainer",
v3_import="from sagemaker.train import ModelTrainer",
)
instance_count = renamed_kwargs(
"train_instance_count", "instance_count", instance_count, kwargs
)
Expand Down
9 changes: 9 additions & 0 deletions src/sagemaker/experiments/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from botocore.exceptions import ClientError

from sagemaker.apiutils import _base_types
from sagemaker.deprecations import warn_v2_deprecation
from sagemaker.experiments.trial import _Trial
from sagemaker.experiments.trial_component import _TrialComponent
from sagemaker.utils import format_tags
Expand Down Expand Up @@ -88,6 +89,10 @@ def load(cls, experiment_name, sagemaker_session=None):
Returns:
experiments.experiment.Experiment: A SageMaker `Experiment` object
"""
warn_v2_deprecation(
feature="Experiment",
v3_replacement="the experiment tracking resources under sagemaker.core.experiments",
)
return cls._construct(
cls._boto_load_method,
experiment_name=experiment_name,
Expand Down Expand Up @@ -121,6 +126,10 @@ def create(
Returns:
experiments.experiment.Experiment: A SageMaker `Experiment` object
"""
warn_v2_deprecation(
feature="Experiment",
v3_replacement="the experiment tracking resources under sagemaker.core.experiments",
)
return cls._construct(
cls._boto_create_method,
experiment_name=experiment_name,
Expand Down
5 changes: 5 additions & 0 deletions src/sagemaker/experiments/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from numpy import array

from sagemaker.apiutils import _utils
from sagemaker.deprecations import warn_v2_deprecation
from sagemaker.experiments import _api_types
from sagemaker.experiments._api_types import (
TrialComponentArtifact,
Expand Down Expand Up @@ -168,6 +169,10 @@ def __init__(
artifact_prefix (str): The S3 key prefix used to generate the S3 path
to upload the artifact to (default: "trial-component-artifacts").
"""
warn_v2_deprecation(
feature="Run",
v3_replacement="the experiment tracking resources under sagemaker.core.experiments",
)
# TODO: we should revert the lower casting once backend fix reaches prod
self.experiment_name = experiment_name.lower()
sagemaker_session = sagemaker_session or _utils.default_session()
Expand Down
5 changes: 5 additions & 0 deletions src/sagemaker/mlflow/tracking_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from __future__ import absolute_import
from typing import Optional, TYPE_CHECKING
from sagemaker.apiutils import _utils
from sagemaker.deprecations import warn_v2_deprecation

if TYPE_CHECKING:
from sagemaker import Session
Expand All @@ -43,6 +44,10 @@ def generate_mlflow_presigned_url(
Returns:
(str): Authorized Url to acess the Mlflow UI.
"""
warn_v2_deprecation(
feature="The MLflow integration",
v3_replacement="the MLflow classes under sagemaker.mlops",
)
session = sagemaker_session or _utils.default_session()
api_response = session.create_presigned_mlflow_tracking_server_url(
name, expires_in_seconds, session_expiration_duration_in_seconds
Expand Down
9 changes: 9 additions & 0 deletions src/sagemaker/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
from sagemaker.model_card.schema_constraints import ModelApprovalStatusEnum
from sagemaker.session import Session
from sagemaker.container_base_model import ContainerBaseModel
from sagemaker.deprecations import warn_v2_deprecation
from sagemaker.model_metrics import ModelMetrics
from sagemaker.drift_check_baselines import DriftCheckBaselines
from sagemaker.explainer import ExplainerConfig
Expand Down Expand Up @@ -340,6 +341,14 @@ def __init__(
content (default: None).

"""
# Reports the concrete subclass name (Model, MultiDataModel,
# JumpStartModel, framework models, ...) since they route through
# Model.__init__.
warn_v2_deprecation(
feature=type(self).__name__,
v3_replacement="ModelBuilder",
v3_import="from sagemaker.serve import ModelBuilder",
)
self.model_data = model_data
self.additional_model_data_sources = additional_model_data_sources
self.image_uri = image_uri
Expand Down
5 changes: 5 additions & 0 deletions src/sagemaker/model_card/model_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from botocore.exceptions import ClientError
from boto3.session import Session as boto3_Session
from six.moves.urllib.parse import urlparse
from sagemaker.deprecations import warn_v2_deprecation
from sagemaker.session import Session

from sagemaker.model_card.schema_constraints import (
Expand Down Expand Up @@ -1433,6 +1434,10 @@ def __init__(
sagemaker_session (Session, optional): A SageMaker Session object, used for SageMaker interactions (default: None). If not specified, a SageMaker Session is created using the default AWS configuration chain.
model_package_details (ModelPackage, optional): Model package version metadata information (default: None).
""" # noqa E501 # pylint: disable=line-too-long
warn_v2_deprecation(
feature="ModelCard",
v3_replacement="the model card resources under sagemaker.core",
)
self.sagemaker_session = sagemaker_session or Session()
self.name = name
self.arn = arn
Expand Down
7 changes: 7 additions & 0 deletions src/sagemaker/model_monitor/model_monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
MONITORING_JOB_OUTPUT_KMS_KEY_ID_PATH,
MONITORING_JOB_ROLE_ARN_PATH,
)
from sagemaker.deprecations import warn_v2_deprecation
from sagemaker.exceptions import UnexpectedStatusException
from sagemaker.model_monitor.monitoring_files import Constraints, ConstraintViolations, Statistics
from sagemaker.model_monitor.monitoring_alert import (
Expand Down Expand Up @@ -170,6 +171,12 @@ def __init__(
inter-container traffic, security group IDs, and subnets.

"""
# Reports the concrete subclass name (ModelMonitor, DefaultModelMonitor,
# ModelQualityMonitor, ...) since they route through ModelMonitor.__init__.
warn_v2_deprecation(
feature=type(self).__name__,
v3_replacement="sagemaker.core.shapes.MonitoringSchedule",
)
self.image_uri = image_uri
self.instance_count = instance_count
self.instance_type = instance_type
Expand Down
6 changes: 6 additions & 0 deletions src/sagemaker/predictor_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from botocore.exceptions import WaiterError

from sagemaker import s3
from sagemaker.deprecations import warn_v2_deprecation
from sagemaker.exceptions import PollingTimeoutError, AsyncInferenceModelError
from sagemaker.async_inference import WaiterConfig, AsyncInferenceResponse
from sagemaker.s3 import parse_s3_url
Expand All @@ -40,6 +41,11 @@ def __init__(
object has useful methods and variables. ``AsyncPredictor``
stands on top of it with capability for async inference.
"""
warn_v2_deprecation(
feature="AsyncPredictor",
v3_replacement="ModelBuilder.deploy(...)",
v3_import="from sagemaker.serve import ModelBuilder",
)
self.predictor = predictor
self.endpoint_name = predictor.endpoint_name
self.sagemaker_session = predictor.sagemaker_session or Session()
Expand Down
9 changes: 9 additions & 0 deletions src/sagemaker/processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
PROCESSING_JOB_VOLUME_KMS_KEY_ID_PATH,
)
from sagemaker.dataset_definition.inputs import DatasetDefinition, S3Input
from sagemaker.deprecations import warn_v2_deprecation
from sagemaker.job import _Job
from sagemaker.local import LocalSession
from sagemaker.network import NetworkConfig
Expand Down Expand Up @@ -131,6 +132,14 @@ def __init__(
object that configures network isolation, encryption of
inter-container traffic, security group IDs, and subnets.
"""
# Reports the concrete subclass name (Processor, ScriptProcessor,
# PySparkProcessor, FrameworkProcessor, SKLearnProcessor, ...) since they
# route through Processor.__init__.
warn_v2_deprecation(
feature=type(self).__name__,
v3_replacement="DataProcessor",
v3_import="from sagemaker.mlops.processing import DataProcessor",
)
self.image_uri = image_uri
self.instance_count = instance_count
self.instance_type = instance_type
Expand Down
5 changes: 5 additions & 0 deletions src/sagemaker/transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
TRANSFORM_RESOURCES_VOLUME_KMS_KEY_ID_PATH,
PIPELINE_ROLE_ARN_PATH,
)
from sagemaker.deprecations import warn_v2_deprecation
from sagemaker.job import _Job
from sagemaker.session import Session, get_execution_role
from sagemaker.inputs import BatchDataCaptureConfig
Expand Down Expand Up @@ -111,6 +112,10 @@ def __init__(
volume_kms_key (str or PipelineVariable): Optional. KMS key ID for encrypting
the volume attached to the ML compute instance (default: None).
"""
warn_v2_deprecation(
feature=type(self).__name__,
v3_replacement="sagemaker.core.shapes.TransformJob",
)
self.model_name = model_name
self.strategy = strategy

Expand Down
9 changes: 8 additions & 1 deletion src/sagemaker/tuner.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
)
from sagemaker.amazon.hyperparameter import Hyperparameter as hp # noqa
from sagemaker.analytics import HyperparameterTuningJobAnalytics
from sagemaker.deprecations import removed_function
from sagemaker.deprecations import removed_function, warn_v2_deprecation
from sagemaker.estimator import EstimatorBase, Framework
from sagemaker.inputs import FileSystemInput, TrainingInput
from sagemaker.job import _Job
Expand Down Expand Up @@ -683,6 +683,13 @@ def __init__(
static and will not be assigned a tunable range with Autotune functionality.
(default: None).
"""
# The migration guide moves HPT to sagemaker-core but does not publish a
# single import path (it spans multiple classes), so we point at the
# namespace and defer to the guide.
warn_v2_deprecation(
feature=type(self).__name__,
v3_replacement="the hyperparameter tuning classes under sagemaker.core",
)
if hyperparameter_ranges is None or len(hyperparameter_ranges) == 0:
if not autotune:
raise ValueError("Need to specify hyperparameter ranges or set autotune=True.")
Expand Down
6 changes: 6 additions & 0 deletions src/sagemaker/workflow/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from sagemaker import s3, LocalSession
from sagemaker._studio import _append_project_tags
from sagemaker.deprecations import warn_v2_deprecation
from sagemaker.config import PIPELINE_ROLE_ARN_PATH, PIPELINE_TAGS_PATH
from sagemaker.remote_function.core.serialization import deserialize_obj_from_s3
from sagemaker.remote_function.core.stored_function import RESULTS_FOLDER
Expand Down Expand Up @@ -115,6 +116,11 @@ def __init__(
the workflow customizes the pipeline definition using the configurations
specified. By default, custom job-prefixing is turned off.
"""
warn_v2_deprecation(
feature="Pipeline",
v3_replacement="Pipeline",
v3_import="from sagemaker.mlops.pipeline import Pipeline",
)
self.name = name
self.parameters = parameters if parameters else []
self.pipeline_experiment_config = pipeline_experiment_config
Expand Down
Loading
Loading