44# This source code is licensed under the BSD-style license found in the
55# LICENSE file in the root directory of this source tree.
66
7+ from __future__ import annotations
8+
79import unittest
8- from collections .abc import AsyncIterator , Iterator
10+ from collections .abc import AsyncIterator , Callable , Iterator
911from contextlib import contextmanager
12+ from typing import Any , cast , TYPE_CHECKING , TypeVar
1013from unittest .mock import MagicMock , patch
1114
1215from spdl .pipeline import (
3033 SourceConfig ,
3134)
3235
36+ if TYPE_CHECKING :
37+ from spdl .pipeline .defs import AggregateConfig , DisaggregateConfig
38+
39+
40+ _T = TypeVar ("_T" )
41+ _U = TypeVar ("_U" )
42+
3343
3444class FetchInputsTest (unittest .TestCase ):
3545 """Test _fetch_inputs functionality."""
3646
37- def test_fetch_inputs (self ):
47+ def test_fetch_inputs (self ) -> None :
3848 """_fetch_inputs collects input items"""
3949 src = SourceConfig (range (10 ))
4050
4151 inputs = _fetch_inputs (src , num_items = 3 )
4252 self .assertEqual (inputs , list (range (3 )))
4353
44- def test_fetch_inputs_async (self ):
54+ def test_fetch_inputs_async (self ) -> None :
4555 """_fetch_inputs collects input items"""
4656
4757 async def arange (n : int ) -> AsyncIterator [int ]:
@@ -62,7 +72,7 @@ def setUp(self) -> None:
6272 config .set_default_profile_hook ()
6373 config .set_default_profile_callback ()
6474
65- def test_profile_pipeline (self ):
75+ def test_profile_pipeline (self ) -> None :
6676 def foo (i : int ) -> int :
6777 return 2 * i
6878
@@ -87,17 +97,27 @@ def bazz(i: int) -> int:
8797 )
8898
8999 class Intercept_ :
100+ assertEqual : Callable [..., None ]
101+ assertIs : Callable [..., None ]
102+
90103 def __init__ (self ) -> None :
91104 self .i = 0
92105
93- def __call__ (self , inputs , pipe , concurrency ):
106+ def __call__ (
107+ self ,
108+ inputs : list [_T ],
109+ pipe : PipeConfig [_T , _U ] | AggregateConfig [_T ] | DisaggregateConfig [_T ],
110+ concurrency : int ,
111+ ) -> PipelineConfig [_U ]:
94112 num_inputs = N if self .i < 2 else (N + m - 1 ) // m
95113 self .assertEqual (len (inputs ), num_inputs )
96114 self .assertEqual (pipe , plc .pipes [self .i ])
97115 ret = _build_pipeline_config (inputs , pipe , concurrency )
98116 self .assertEqual (len (ret .pipes ), 1 )
99117 if isinstance (pipe , PipeConfig ):
100- self .assertIs (ret .pipes [0 ]._args .op , plc .pipes [self .i ]._args .op )
118+ ret_pipe = cast ("PipeConfig[Any, Any]" , ret .pipes [0 ])
119+ plc_pipe = cast ("PipeConfig[Any, Any]" , plc .pipes [self .i ])
120+ self .assertIs (ret_pipe ._args .op , plc_pipe ._args .op )
101121 self .i += 1
102122 return ret
103123
@@ -109,7 +129,7 @@ def __call__(self, inputs, pipe, concurrency):
109129
110130 self .assertEqual (mock .i , 5 )
111131
112- def test_profile_pipeline_callback (self ):
132+ def test_profile_pipeline_callback (self ) -> None :
113133 """Test that profile_pipeline calls the callback for each pipe stage."""
114134
115135 def simple_op (i : int ) -> int :
@@ -139,7 +159,7 @@ def simple_op(i: int) -> int:
139159 self .assertEqual (results [0 ].name , called_result .name )
140160 self .assertEqual (len (results [0 ].stats ), len (called_result .stats ))
141161
142- def test_profile_pipeline_no_callback (self ):
162+ def test_profile_pipeline_no_callback (self ) -> None :
143163 """Test that profile_pipeline works correctly when no callback is provided."""
144164
145165 def simple_op (i : int ) -> int :
@@ -168,7 +188,7 @@ def setUp(self) -> None:
168188 config .set_default_profile_hook ()
169189 config .set_default_profile_callback ()
170190
171- def test_profile_pipeline_custom_hook_methods_called (self ):
191+ def test_profile_pipeline_custom_hook_methods_called (self ) -> None :
172192 """Test that custom ProfileHook's stage_profile_hook and
173193 pipeline_profile_hook methods are called.
174194 """
@@ -190,7 +210,9 @@ def simple_op(i: int) -> int:
190210 class MockProfileHook (ProfileHook ):
191211 @contextmanager
192212 def stage_profile_hook (
193- self , _stage : str , _concurrency : int
213+ self ,
214+ stage : str , # noqa: ARG002
215+ concurrency : int , # noqa: ARG002
194216 ) -> Iterator [None ]:
195217 stage_hook_mock ()
196218 try :
@@ -214,7 +236,7 @@ def pipeline_profile_hook(self) -> Iterator[None]:
214236 self .assertEqual (pipeline_hook_mock .call_count , 2 )
215237 self .assertEqual (stage_hook_mock .call_count , 10 )
216238
217- def test_profile_pipeline_skips_when_local_rank_not_zero (self ):
239+ def test_profile_pipeline_skips_when_local_rank_not_zero (self ) -> None :
218240 """Test that profiling is skipped if LOCAL_RANK is not '0'."""
219241
220242 def simple_op (i : int ) -> int :
@@ -233,7 +255,7 @@ def simple_op(i: int) -> int:
233255
234256 self .assertEqual (results , [])
235257
236- def test_profile_pipeline_runs_when_local_rank_zero (self ):
258+ def test_profile_pipeline_runs_when_local_rank_zero (self ) -> None :
237259 """Test that profiling runs normally when LOCAL_RANK is '0'."""
238260
239261 def simple_op (i : int ) -> int :
@@ -263,7 +285,7 @@ def setUp(self) -> None:
263285 config .set_default_profile_hook ()
264286 config .set_default_profile_callback ()
265287
266- def test_profile_pipeline_with_merge_config_and_post_merge_stages (self ):
288+ def test_profile_pipeline_with_merge_config_and_post_merge_stages (self ) -> None :
267289 """Test that profile_pipeline profiles all stages including
268290 those in Merge and post-merge stages.
269291 """
0 commit comments