Skip to content

Commit f502406

Browse files
mohamedzeidan2021Mohamed Zeidan
andauthored
fix: do not apply user ignore_patterns to the SDK-owned sm_drivers channel (#6328)
ModelTrainer forwarded the user's source_code.ignore_patterns to the sm_drivers input channel, which packages SDK-owned driver content (e.g. container_drivers/scripts/environment.py). User patterns such as "scripts" or "environment" then stripped files the container bootstrap requires, failing execution with "sm_drivers/scripts/environment.py: No such file or directory". Drop the ignore_patterns argument on the sm_drivers channel so it uploads unfiltered; user patterns still apply to the user's own source_dir (SM_CODE) channel. Also corrects the create_input_data_channel docstring, which wrongly claimed a default filter list (the default is None -> no filter). Adds a regression test asserting SM_CODE keeps the user patterns and SM_DRIVERS receives none. Fixes #5493 Co-authored-by: Mohamed Zeidan <zeidmo@amazon.com>
1 parent 6bf17a5 commit f502406

2 files changed

Lines changed: 48 additions & 4 deletions

File tree

‎src/sagemaker/modules/train/model_trainer.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -717,12 +717,15 @@ def _create_training_job_args(
717717
self._write_source_code_json(tmp_dir=self._temp_code_dir, source_code=self.source_code)
718718
self._write_distributed_json(tmp_dir=self._temp_code_dir, distributed=self.distributed)
719719

720-
# Create an input channel for drivers packaged by the sdk
720+
# Create an input channel for drivers packaged by the sdk.
721+
# Do NOT apply the user's source_code.ignore_patterns here: this directory is
722+
# SDK-owned driver content (e.g. scripts/environment.py), and user patterns such as
723+
# "scripts" or "environment" would strip files the container bootstrap requires,
724+
# causing "sm_drivers/scripts/environment.py: No such file or directory" (issue #5493).
721725
sm_drivers_channel = self.create_input_data_channel(
722726
channel_name=SM_DRIVERS,
723727
data_source=self._temp_code_dir.name,
724728
key_prefix=input_data_key_prefix,
725-
ignore_patterns=self.source_code.ignore_patterns,
726729
)
727730
final_input_data_config.append(sm_drivers_channel)
728731

@@ -881,8 +884,7 @@ def create_input_data_channel(
881884
``s3://<default_bucket_path>/<key_prefix>/<channel_name>/``
882885
ignore_patterns: (Optional[List[str]]) :
883886
The ignore patterns to ignore specific files/folders when uploading to S3.
884-
If not specified, default to: ['.env', '.git', '__pycache__', '.DS_Store',
885-
'.cache', '.ipynb_checkpoints'].
887+
If not specified, no files are filtered and the data source is uploaded as-is.
886888
"""
887889
channel = None
888890
if isinstance(data_source, str):

‎tests/unit/sagemaker/modules/train/test_model_trainer.py‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
DataSource,
6969
MetricDefinition,
7070
)
71+
from sagemaker.modules.constants import SM_CODE, SM_DRIVERS
7172
from sagemaker.modules.distributed import Torchrun, SMP, MPI
7273
from sagemaker.modules.train.sm_recipes.utils import _load_recipes_cfg
7374
from sagemaker.modules.templates import EXEUCTE_DISTRIBUTED_DRIVER
@@ -254,6 +255,47 @@ def test_train_with_default_params(mock_training_job, model_trainer):
254255
training_job_instance.wait.assert_called_once_with(logs=True)
255256

256257

258+
@patch("sagemaker.modules.train.model_trainer.TrainingJob")
259+
@patch("sagemaker.modules.train.model_trainer.ModelTrainer.create_input_data_channel")
260+
def test_sm_drivers_channel_ignores_user_ignore_patterns(
261+
mock_create_input_data_channel, mock_training_job, modules_session
262+
):
263+
"""Regression for #5493.
264+
265+
The user's ``ignore_patterns`` apply only to their own source_dir channel. They must NOT be
266+
forwarded to the SDK-owned ``sm_drivers`` driver channel -- patterns like ``"scripts"`` or
267+
``"environment"`` would strip the driver's own ``scripts/environment.py`` and break the
268+
container bootstrap with "sm_drivers/scripts/environment.py: No such file or directory".
269+
"""
270+
user_patterns = ["scripts", "environment", "data"]
271+
trainer = ModelTrainer(
272+
training_image=DEFAULT_IMAGE,
273+
role=DEFAULT_ROLE,
274+
compute=DEFAULT_COMPUTE_CONFIG,
275+
stopping_condition=DEFAULT_STOPPING_CONDITION,
276+
output_data_config=DEFAULT_OUTPUT_DATA_CONFIG,
277+
source_code=SourceCode(
278+
source_dir=DEFAULT_SOURCE_DIR,
279+
entry_script="custom_script.py",
280+
ignore_patterns=user_patterns,
281+
),
282+
sagemaker_session=modules_session,
283+
)
284+
285+
trainer.train()
286+
287+
calls_by_channel = {
288+
call.kwargs.get("channel_name"): call.kwargs
289+
for call in mock_create_input_data_channel.call_args_list
290+
}
291+
assert SM_CODE in calls_by_channel, "source_dir channel was not created"
292+
assert SM_DRIVERS in calls_by_channel, "sm_drivers channel was not created"
293+
# User patterns still apply to the user's own source_dir channel.
294+
assert calls_by_channel[SM_CODE].get("ignore_patterns") == user_patterns
295+
# ...but must NOT be applied to the SDK-owned driver channel.
296+
assert calls_by_channel[SM_DRIVERS].get("ignore_patterns") is None
297+
298+
257299
@pytest.mark.parametrize(
258300
"default_config",
259301
[

0 commit comments

Comments
 (0)