Skip to content
Open
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
16 changes: 15 additions & 1 deletion sagemaker-core/src/sagemaker/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
"""Namespace package for SageMaker."""
__path__ = __import__('pkgutil').extend_path(__path__, __name__)

__path__ = __import__("pkgutil").extend_path(__path__, __name__)

# Register the fallback finder that gives actionable migration guidance for v2
# modules removed in v3. Doing it here (in the namespace package init, which
# runs on any ``import sagemaker.*``) ensures the guidance is active even when a
# removed module is the very first sagemaker import in the process (e.g.
# ``import sagemaker.estimator``), before ``sagemaker.core`` is otherwise loaded.
# Fully guarded so it can never interfere with importing the package.
try:
from sagemaker.core.deprecations import register_removed_module_finder as _register

_register()
except Exception: # pylint: disable=W0703 # noqa: E722
pass
27 changes: 27 additions & 0 deletions sagemaker-core/src/sagemaker/algorithm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 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.
"""Removed in v3. This module stood in the v2 SageMaker Python SDK.

Importing ``sagemaker.algorithm`` raises an actionable ``ModuleNotFoundError`` that
points to the v3 replacement. See the migration guide for details.
"""
from __future__ import absolute_import

from sagemaker.core.deprecations import raise_removed_in_v3

raise_removed_in_v3(
module="sagemaker.algorithm",
replacement="`ModelTrainer`",
v3_import="from sagemaker.train import ModelTrainer",
v3_docs="https://sagemaker.readthedocs.io/en/stable/api/generated/sagemaker.train.model_trainer.html",
)
27 changes: 27 additions & 0 deletions sagemaker-core/src/sagemaker/automl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 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.
"""Removed in v3. This module stood in the v2 SageMaker Python SDK.

Importing ``sagemaker.automl`` raises an actionable ``ModuleNotFoundError`` that
points to the v3 replacement. See the migration guide for details.
"""
from __future__ import absolute_import

from sagemaker.core.deprecations import raise_removed_in_v3

raise_removed_in_v3(
module="sagemaker.automl",
replacement="the `AutoMLJob` resource",
v3_import="from sagemaker.core.resources import AutoMLJob",
v3_docs="https://sagemaker.readthedocs.io/en/stable/api/generated/sagemaker.core.resources.html",
)
27 changes: 27 additions & 0 deletions sagemaker-core/src/sagemaker/base_predictor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 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.
"""Removed in v3. This module stood in the v2 SageMaker Python SDK.

Importing ``sagemaker.base_predictor`` raises an actionable ``ModuleNotFoundError`` that
points to the v3 replacement. See the migration guide for details.
"""
from __future__ import absolute_import

from sagemaker.core.deprecations import raise_removed_in_v3

raise_removed_in_v3(
module="sagemaker.base_predictor",
replacement="the `Endpoint` resource",
v3_import="from sagemaker.core.resources import Endpoint",
v3_docs="https://sagemaker.readthedocs.io/en/stable/api/generated/sagemaker.core.resources.html",
)
8 changes: 8 additions & 0 deletions sagemaker-core/src/sagemaker/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
"""SageMaker Core package for low-level resource management and SDK foundations."""

from sagemaker.core.utils.utils import enable_textual_rich_console_and_traceback
from sagemaker.core.deprecations import register_removed_module_finder


enable_textual_rich_console_and_traceback()

# Install the fallback finder that gives actionable migration guidance for v2
# modules removed in v3 but not individually tombstoned. sagemaker-core is the
# universal dependency of every v3 package, so registering here guarantees the
# finder is active whenever the SDK is used.
register_removed_module_finder()

# Job management
from sagemaker.core.job import _Job # noqa: F401
from sagemaker.core.processing import ( # noqa: F401
Expand Down
223 changes: 223 additions & 0 deletions sagemaker-core/src/sagemaker/core/deprecations.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,236 @@
"""Module for deprecation abstractions."""
from __future__ import absolute_import

import importlib.abc
import logging
import sys
import warnings

logger = logging.getLogger(__name__)

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

# Migration guide for users moving from the v2 SDK to v3.
V3_MIGRATION_URL = "https://github.com/aws/sagemaker-python-sdk/blob/master/migration.md"

# Real top-level ``sagemaker.*`` names that ship in v3. The fallback finder must
# never intercept these -- even when a package (e.g. sagemaker-train) is simply
# not installed, its absence should surface the normal error, not a bogus
# "removed in v3" message.
_KNOWN_V3_TOPLEVEL = frozenset({"core", "train", "serve", "mlops", "lineage", "ai_registry"})

# Top-level ``sagemaker.<name>`` modules that existed in v2 but were removed in
# v3 (some relocated under ``sagemaker.core.*``). Derived from the v2 top-level
# module surface (the ``master-v2`` branch), minus names that still exist in v3.
# The fallback finder only emits migration guidance for THESE names, so a typo
# or hallucinated import (e.g. ``sagemaker.foobar``) gets a plain
# ``ModuleNotFoundError`` rather than a misleading "was removed" message. V2 is
# in maintenance, so this surface is effectively frozen.
_REMOVED_V2_MODULES = frozenset(
{
"_studio",
"accept_types",
"algorithm",
"amazon",
"amtviz",
"analytics",
"apiutils",
"async_inference",
"automl",
"aws_batch",
"base_deserializers",
"base_predictor",
"base_serializers",
"batch_inference",
"chainer",
"clarify",
"cli",
"collection",
"compute_resource_requirements",
"config",
"container_base_model",
"content_types",
"dataset_definition",
"debugger",
"deprecations",
"deserializers",
"djl_inference",
"drift_check_baselines",
"enums",
"environment_variables",
"estimator",
"exceptions",
"experiments",
"explainer",
"feature_store",
"fw_utils",
"git_utils",
"huggingface",
"hyperparameters",
"image_uri_config",
"image_uris",
"inference_recommender",
"inputs",
"instance_group",
"instance_types",
"instance_types_gpu_info",
"interactive_apps",
"iterators",
"job",
"jumpstart",
"lambda_helper",
"local",
"logs",
"metadata_properties",
"metric_definitions",
"mlflow",
"model",
"model_card",
"model_life_cycle",
"model_metrics",
"model_monitor",
"model_uris",
"modules",
"multidatamodel",
"mxnet",
"network",
"parameter",
"partner_app",
"payloads",
"pipeline",
"predictor",
"predictor_async",
"processing",
"pytorch",
"remote_function",
"resource_requirements",
"rl",
"s3",
"s3_utils",
"script_uris",
"serializer_utils",
"serializers",
"serverless",
"session",
"session_settings",
"sklearn",
"spark",
"sparkml",
"stabilityai",
"telemetry",
"tensorflow",
"training_compiler",
"transformer",
"tuner",
"user_agent",
"utilities",
"utils",
"vpc_utils",
"workflow",
"wrangler",
"xgboost",
}
)


def raise_removed_in_v3(module, replacement=None, v3_import=None, v3_docs=None):
"""Warn and then raise an actionable error for a v2 module removed in v3.

The v2 SDK exposed top-level modules (e.g. ``sagemaker.estimator``) that no
longer exist in v3. Importing one would otherwise fail with a bare
``ModuleNotFoundError: No module named 'sagemaker.estimator'`` that gives the
caller no path forward. This helper is called from lightweight "tombstone"
modules that stand in for those removed names: it emits a
``DeprecationWarning`` and then raises a ``ModuleNotFoundError`` whose message
names the exact v3 replacement, the import to copy-paste, and a direct link
to that replacement's API docs (plus the migration guide).

Args:
module (str): The removed v2 module path, e.g. ``"sagemaker.estimator"``.
replacement (str): Human readable v3 replacement, e.g. ``"ModelTrainer"``.
Optional.
v3_import (str): The exact v3 import statement, e.g.
``"from sagemaker.train import ModelTrainer"``. Quoted verbatim so the
caller can copy-paste it. Optional.
v3_docs (str): Direct URL to the v3 replacement's API documentation, e.g.
the generated ``sagemaker.train.model_trainer`` page. Optional.

Raises:
ModuleNotFoundError: always, after emitting the deprecation warning.
"""
msg = f"`{module}` was removed in the SageMaker Python SDK v3."
if replacement:
msg += f" Use {replacement}."
if v3_import:
msg += f" ({v3_import})"
if v3_docs:
msg += f"\nDocs: {v3_docs}"
msg += f"\nSee {V3_MIGRATION_URL} for the migration guide."

warnings.warn(msg, DeprecationWarning, stacklevel=2)
# The raised ModuleNotFoundError below is the loud, authoritative signal
# (it stops execution and carries the full message). Log at debug only, to
# leave a breadcrumb for log-captured environments without duplicating the
# message at WARNING level.
logger.debug(msg)
raise ModuleNotFoundError(msg, name=module)


class _RemovedV2ModuleFinder(importlib.abc.MetaPathFinder):
"""Fallback finder that gives actionable guidance for removed v2 modules.

Curated removals ship as explicit "tombstone" modules (e.g.
``sagemaker/estimator.py``) that raise a precise, per-module message. This
finder is the *catch-all* for every other ``sagemaker.<name>`` that existed
in v2 but was not individually tombstoned: instead of a bare
``ModuleNotFoundError: No module named 'sagemaker.foo'``, the caller gets a
message that says the module is not available in v3 and points to the
migration guide.

It is registered by appending to ``sys.meta_path``, so it only runs *after*
the normal import machinery has failed to locate the module. That ordering
guarantees it never shadows:
- real v3 packages (``sagemaker.core``, ``sagemaker.train``, ...), and
- the curated tombstone modules, which resolve as ordinary files first.
"""

def find_spec(self, fullname, path=None, target=None):
"""Emit guidance only for known removed v2 top-level ``sagemaker`` modules."""
if not fullname.startswith("sagemaker."):
return None
leaf = fullname[len("sagemaker.") :]
# Only guard top-level names; never touch real v3 subpackages.
if "." in leaf or leaf in _KNOWN_V3_TOPLEVEL:
return None
# Only guard names that were actually v2 modules. Unknown names (typos,
# hallucinated imports) fall through to a plain ModuleNotFoundError so we
# never claim something "was removed" when it never existed.
if leaf not in _REMOVED_V2_MODULES:
return None

msg = (
f"`{fullname}` was removed in the SageMaker Python SDK v3. "
"It may have moved to a new location."
f"\nSee {V3_MIGRATION_URL} for the migration guide."
)
warnings.warn(msg, DeprecationWarning, stacklevel=2)
# See raise_removed_in_v3: the raised error is the loud signal; log at
# debug to avoid duplicating the message at WARNING level.
logger.debug(msg)
raise ModuleNotFoundError(msg, name=fullname)


def register_removed_module_finder():
"""Install the fallback finder for removed v2 modules (idempotent).

Appends a single ``_RemovedV2ModuleFinder`` to ``sys.meta_path`` so it acts
as a last resort. Safe to call multiple times -- it installs at most one
instance per process.
"""
if any(isinstance(f, _RemovedV2ModuleFinder) for f in sys.meta_path):
return
sys.meta_path.append(_RemovedV2ModuleFinder())


def _warn(msg, sdk_version=None):
"""Generic warning raiser referencing V2
Expand Down
27 changes: 27 additions & 0 deletions sagemaker-core/src/sagemaker/estimator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 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.
"""Removed in v3. This module stood in the v2 SageMaker Python SDK.

Importing ``sagemaker.estimator`` raises an actionable ``ModuleNotFoundError`` that
points to the v3 replacement. See the migration guide for details.
"""
from __future__ import absolute_import

from sagemaker.core.deprecations import raise_removed_in_v3

raise_removed_in_v3(
module="sagemaker.estimator",
replacement="`ModelTrainer`",
v3_import="from sagemaker.train import ModelTrainer",
v3_docs="https://sagemaker.readthedocs.io/en/stable/api/generated/sagemaker.train.model_trainer.html",
)
Loading
Loading