1313from __future__ import annotations
1414
1515import inspect
16+ from pathlib import Path
1617from unittest .mock import MagicMock , patch
1718
1819import pytest
1920
2021from deeplabcut .api import _tf_routing as tf_routing
22+ from deeplabcut .core .config import ProjectConfig
2123from deeplabcut .core .deprecation import DLCDeprecationWarning
2224from deeplabcut .core .engine import Engine
2325
@@ -203,14 +205,17 @@ def test_resolve_legacy_kwargs_does_not_mutate_renamed_params():
203205# ---------------------------------------------------------------------------
204206
205207
206- def test_resolve_engine_uses_explicit_engine ():
208+ @patch ("deeplabcut.generate_training_dataset.metadata.get_shuffle_engine" , return_value = Engine .TF )
209+ def test_resolve_engine_uses_explicit_engine_without_metadata_lookup (mock_get_shuffle_engine ):
210+ """An explicit engine short-circuits resolution, so the config is never read."""
207211 engine = tf_routing ._resolve_engine ({"config" : "cfg.yaml" , "engine" : Engine .PYTORCH })
212+
208213 assert engine == Engine .PYTORCH
214+ mock_get_shuffle_engine .assert_not_called ()
209215
210216
211217@patch ("deeplabcut.generate_training_dataset.metadata.get_shuffle_engine" , return_value = Engine .PYTORCH )
212- @patch ("deeplabcut.core.config.utils.read_config" , return_value = {"project_path" : "/tmp" })
213- def test_resolve_engine_from_shuffle_metadata (mock_read_config , mock_get_shuffle_engine ):
218+ def test_resolve_engine_from_shuffle_metadata (mock_get_shuffle_engine ):
214219 engine = tf_routing ._resolve_engine (
215220 {
216221 "config" : "cfg.yaml" ,
@@ -221,32 +226,37 @@ def test_resolve_engine_from_shuffle_metadata(mock_read_config, mock_get_shuffle
221226 )
222227
223228 assert engine == Engine .PYTORCH
224- mock_read_config .assert_called_once_with ("cfg.yaml" )
225229 mock_get_shuffle_engine .assert_called_once_with (
226- { "project_path" : "/tmp" } ,
230+ "cfg.yaml" ,
227231 trainingsetindex = 1 ,
228232 shuffle = 2 ,
229233 modelprefix = "prefix" ,
230234 )
231235
232236
237+ @pytest .mark .parametrize (
238+ "config" ,
239+ ["cfg.yaml" , Path ("cfg.yaml" ), {"project_path" : "/tmp" }, ProjectConfig (project_path = "/tmp" )],
240+ ids = ["str" , "path" , "dict" , "project_config" ],
241+ )
233242@patch ("deeplabcut.generate_training_dataset.metadata.get_shuffle_engine" , return_value = Engine .PYTORCH )
234- @patch ("deeplabcut.core.config.utils.read_config" , return_value = {"project_path" : "/tmp" })
235- def test_resolve_engine_defaults_to_shuffle_one (mock_read_config , mock_get_shuffle_engine ):
236- engine = tf_routing ._resolve_engine ({"config" : "cfg.yaml" })
243+ def test_resolve_engine_forwards_config_as_is_and_defaults_to_shuffle_one (mock_get_shuffle_engine , config ):
244+ """Config is forwarded untouched, and shuffle defaults to 1 when none is given.
245+ ``get_shuffle_engine`` accepts ProjectConfig | dict | Path | str
246+ """
247+ engine = tf_routing ._resolve_engine ({"config" : config })
237248
238249 assert engine == Engine .PYTORCH
239250 mock_get_shuffle_engine .assert_called_once_with (
240- { "project_path" : "/tmp" } ,
251+ config ,
241252 trainingsetindex = 0 ,
242253 shuffle = 1 ,
243254 modelprefix = "" ,
244255 )
245256
246257
247258@patch ("deeplabcut.generate_training_dataset.metadata.get_shuffle_engine" )
248- @patch ("deeplabcut.core.config.utils.read_config" , return_value = {"project_path" : "/tmp" })
249- def test_resolve_engine_from_shuffles_list (mock_read_config , mock_get_shuffle_engine ):
259+ def test_resolve_engine_from_shuffles_list (mock_get_shuffle_engine ):
250260 mock_get_shuffle_engine .side_effect = [Engine .PYTORCH , Engine .PYTORCH ]
251261
252262 engine = tf_routing ._resolve_engine ({"config" : "cfg.yaml" , "shuffles" : [1 , 2 ]})
@@ -256,20 +266,19 @@ def test_resolve_engine_from_shuffles_list(mock_read_config, mock_get_shuffle_en
256266
257267
258268@patch ("deeplabcut.generate_training_dataset.metadata.get_shuffle_engine" , return_value = Engine .TF )
259- @patch ("deeplabcut.core.config.utils.read_config" , return_value = {"project_path" : "/tmp" })
260- def test_resolve_engine_accepts_legacy_shuffles_kwarg (mock_read_config , mock_get_shuffle_engine ):
269+ def test_resolve_engine_accepts_legacy_shuffles_kwarg (mock_get_shuffle_engine ):
261270 engine = tf_routing ._resolve_engine ({"config" : "cfg.yaml" , "Shuffles" : [2 , 3 ]})
262271
263272 assert engine == Engine .TF
264273 assert mock_get_shuffle_engine .call_count == 2
265274 mock_get_shuffle_engine .assert_any_call (
266- { "project_path" : "/tmp" } ,
275+ "cfg.yaml" ,
267276 trainingsetindex = 0 ,
268277 shuffle = 2 ,
269278 modelprefix = "" ,
270279 )
271280 mock_get_shuffle_engine .assert_any_call (
272- { "project_path" : "/tmp" } ,
281+ "cfg.yaml" ,
273282 trainingsetindex = 0 ,
274283 shuffle = 3 ,
275284 modelprefix = "" ,
@@ -288,22 +297,13 @@ def test_resolve_engine_raises_on_emplty_shuffles(shuffles):
288297
289298
290299@patch ("deeplabcut.generate_training_dataset.metadata.get_shuffle_engine" )
291- @patch ("deeplabcut.core.config.utils.read_config" , return_value = {"project_path" : "/tmp" })
292- def test_resolve_engine_raises_when_shuffles_have_different_engines (mock_read_config , mock_get_shuffle_engine ):
300+ def test_resolve_engine_raises_when_shuffles_have_different_engines (mock_get_shuffle_engine ):
293301 mock_get_shuffle_engine .side_effect = [Engine .PYTORCH , Engine .TF ]
294302
295303 with pytest .raises (ValueError , match = "All shuffles must have the same engine" ):
296304 tf_routing ._resolve_engine ({"config" : "cfg.yaml" , "shuffles" : [1 , 2 ]})
297305
298306
299- @patch ("deeplabcut.core.config.utils.read_config" , return_value = {"project_path" : "/tmp" })
300- def test_resolve_engine_reads_config_from_kwargs (mock_read_config ):
301- with patch ("deeplabcut.generate_training_dataset.metadata.get_shuffle_engine" , return_value = Engine .PYTORCH ):
302- tf_routing ._resolve_engine ({"config" : "other.yaml" , "engine" : Engine .PYTORCH })
303-
304- mock_read_config .assert_not_called ()
305-
306-
307307# ---------------------------------------------------------------------------
308308# warn_deprecated_tensorflow
309309# ---------------------------------------------------------------------------
@@ -598,12 +598,14 @@ def canonical_fn(path: str, model_name: str, **kwargs):
598598
599599def test_with_tensorflow_fallback_forwards_legacy_alias_to_renamed_parameter ():
600600 """Router must not swallow legacy alias before inner @renamed_parameter."""
601- from deeplabcut .core .deprecation import renamed_parameter
601+ from deeplabcut .core .deprecation import DeprecationRound , renamed_parameter
602602
603603 pytorch_fn = MagicMock (return_value = "pytorch" )
604604
605605 @tf_routing .with_tensorflow_fallback
606- @renamed_parameter (old = "displayiters" , new = "display_iters" , since = "3.0.0" )
606+ @renamed_parameter (
607+ old = "displayiters" , new = "display_iters" , deprecation_round = DeprecationRound .INIT_PARAMETER_ALIASING
608+ )
607609 def canonical_fn (config : str , display_iters : int | None = None ):
608610 return pytorch_fn (config , display_iters = display_iters )
609611
0 commit comments