Skip to content

Commit d3ecfae

Browse files
committed
fix: Pipeline TypeError: can only concatenate list (not "NoneType") to list Using Sou (#5518)
1 parent ee420cc commit d3ecfae

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

sagemaker-core/tests/unit/workflow/test_utilities.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from sagemaker.core.workflow.entities import Entity
3333
from sagemaker.core.workflow.parameters import Parameter
3434
from sagemaker.core.workflow.pipeline_context import _StepArguments
35+
from sagemaker.core.workflow.utilities import get_code_hash
3536

3637

3738
class MockEntity(Entity):
@@ -308,6 +309,49 @@ def test_get_training_code_hash_entry_point_only(self):
308309
assert len(result_with_deps) == 64
309310
assert result_no_deps != result_with_deps
310311

312+
def test_get_training_code_hash_with_source_dir_none_dependencies(self):
313+
"""Test get_training_code_hash with source_dir and None dependencies does not raise TypeError"""
314+
with tempfile.TemporaryDirectory() as temp_dir:
315+
entry_file = Path(temp_dir, "train.py")
316+
entry_file.write_text("print('training')")
317+
318+
# This is the exact scenario from the bug report: dependencies=None
319+
result = get_training_code_hash(
320+
entry_point=str(entry_file), source_dir=temp_dir, dependencies=None
321+
)
322+
323+
assert result is not None
324+
assert len(result) == 64
325+
326+
def test_get_training_code_hash_entry_point_only_none_dependencies(self):
327+
"""Test get_training_code_hash with entry_point only and None dependencies does not raise TypeError"""
328+
with tempfile.TemporaryDirectory() as temp_dir:
329+
entry_file = Path(temp_dir, "train.py")
330+
entry_file.write_text("print('training')")
331+
332+
# entry_point only, no source_dir, dependencies=None
333+
result = get_training_code_hash(
334+
entry_point=str(entry_file), source_dir=None, dependencies=None
335+
)
336+
337+
assert result is not None
338+
assert len(result) == 64
339+
340+
def test_get_training_code_hash_default_dependencies(self):
341+
"""Test get_training_code_hash with default dependencies parameter (not passed)"""
342+
with tempfile.TemporaryDirectory() as temp_dir:
343+
entry_file = Path(temp_dir, "train.py")
344+
entry_file.write_text("print('training')")
345+
346+
# Not passing dependencies at all - should use default None
347+
result = get_training_code_hash(
348+
entry_point=str(entry_file), source_dir=temp_dir
349+
)
350+
351+
assert result is not None
352+
assert len(result) == 64
353+
354+
311355
def test_get_training_code_hash_s3_uri(self):
312356
"""Test get_training_code_hash with S3 URI returns None"""
313357
result = get_training_code_hash(
@@ -325,6 +369,54 @@ def test_get_training_code_hash_pipeline_variable(self):
325369

326370
assert result is None
327371

372+
@pytest.mark.skip(reason="Requires sagemaker-mlops module which is not installed in sagemaker-core tests")
373+
def test_get_code_hash_training_step_none_requirements(self):
374+
"""Test get_code_hash with TrainingStep where source_code.requirements is None"""
375+
from sagemaker.mlops.workflow.steps import TrainingStep
376+
377+
with tempfile.TemporaryDirectory() as temp_dir:
378+
entry_file = Path(temp_dir, "train.py")
379+
entry_file.write_text("print('training')")
380+
381+
mock_source_code = Mock()
382+
mock_source_code.source_dir = temp_dir
383+
mock_source_code.requirements = None # This is the bug scenario
384+
mock_source_code.entry_script = str(entry_file)
385+
386+
mock_model_trainer = Mock()
387+
mock_model_trainer.source_code = mock_source_code
388+
389+
mock_step_args = Mock(spec=_StepArguments)
390+
mock_step_args.func_args = [mock_model_trainer]
391+
392+
mock_step = Mock(spec=TrainingStep)
393+
mock_step.step_args = mock_step_args
394+
395+
# This should not raise TypeError
396+
result = get_code_hash(mock_step)
397+
398+
assert result is not None
399+
assert len(result) == 64
400+
401+
@pytest.mark.skip(reason="Requires sagemaker-mlops module which is not installed in sagemaker-core tests")
402+
def test_get_code_hash_training_step_no_source_code(self):
403+
"""Test get_code_hash with TrainingStep where source_code is None"""
404+
from sagemaker.mlops.workflow.steps import TrainingStep
405+
406+
mock_model_trainer = Mock()
407+
mock_model_trainer.source_code = None
408+
409+
mock_step_args = Mock(spec=_StepArguments)
410+
mock_step_args.func_args = [mock_model_trainer]
411+
412+
mock_step = Mock(spec=TrainingStep)
413+
mock_step.step_args = mock_step_args
414+
415+
result = get_code_hash(mock_step)
416+
417+
assert result is None
418+
419+
328420
def test_validate_step_args_input_valid(self):
329421
"""Test validate_step_args_input with valid input"""
330422
step_args = _StepArguments(

0 commit comments

Comments
 (0)