Defer boto3 import and raise actionable ImportError for s3:// loads (#489)

*Issue #, if available:*

*Description of changes:*
- `boto3` lives in `[project.optional-dependencies].extras`, but
`src/chronos/boto_utils.py` imported it (and `botocore`) at module top.
A user who installs the package with `pip install chronos-forecasting`
(no extras) and then calls `from_pretrained("s3://...")` currently hits
a bare `ModuleNotFoundError: No module named 'boto3'` with no hint about
the `extras` group.
- Defer `boto3` / `botocore` imports in `src/chronos/boto_utils.py` into
the single function that actually uses them
(`download_model_files_from_s3`) and move the `boto3.Session` annotation
behind `from __future__ import annotations` + a `TYPE_CHECKING` block,
so importing the package no longer fails when `boto3` is absent.
- In `src/chronos/base.py` (inside
`BaseChronosPipeline.from_pretrained`, around line 349) wrap the
`cache_model_from_s3(...)` call in `try/except ImportError` and re-raise
with a message that tells the user to run `pip install
'chronos-forecasting[extras]'`. HuggingFace Hub and local-path loads are
unaffected.
- Verified locally in a fresh venv (no `[extras]`): `from chronos import
BaseChronosPipeline` succeeds,
`BaseChronosPipeline.from_pretrained("s3://...")` now raises the
actionable `ImportError` instead of the bare `ModuleNotFoundError`.


By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

Co-authored-by: Abdul Fatir <Abdulfatirs@gmail.com>
This commit is contained in:
Junghwan 2026-04-21 22:05:50 +09:00 committed by GitHub
parent ea10d73fbb
commit 32111085d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 21 additions and 7 deletions

View file

@ -348,9 +348,16 @@ class BaseChronosPipeline(metaclass=PipelineRegistry):
if str(pretrained_model_name_or_path).startswith("s3://"):
from .boto_utils import cache_model_from_s3
local_model_path = cache_model_from_s3(
str(pretrained_model_name_or_path), force_download=force_s3_download
)
try:
local_model_path = cache_model_from_s3(
str(pretrained_model_name_or_path), force_download=force_s3_download
)
except ImportError as e:
raise ImportError(
"Loading models from s3:// URIs requires boto3. "
"Install the optional dependencies with: "
"pip install 'chronos-forecasting[extras]'"
) from e
return cls.from_pretrained(local_model_path, *model_args, **kwargs)
from transformers import AutoConfig

View file

@ -3,17 +3,19 @@
# Authors: Abdul Fatir Ansari <ansarnd@amazon.com>
from __future__ import annotations
import logging
import os
import re
import warnings
from pathlib import Path
from typing import TYPE_CHECKING
import boto3
import requests # type: ignore
from botocore import UNSIGNED
from botocore.client import Config
from botocore.exceptions import ClientError, NoCredentialsError
if TYPE_CHECKING:
import boto3
logger = logging.getLogger(__name__)
@ -57,6 +59,11 @@ def download_model_files_from_s3(
force_download: bool = False,
boto3_session: boto3.Session | None = None,
) -> None:
import boto3
from botocore import UNSIGNED
from botocore.client import Config
from botocore.exceptions import ClientError, NoCredentialsError
boto3_session = boto3_session or boto3.Session()
s3_client = boto3_session.client("s3")