@@ -96,6 +96,27 @@ def test_characterization_infers_correct_class_namespace(
9696 assert call_kwargs .get ("pretrain_weights" ) == str (tmp_path / "ckpt.pth" )
9797 assert result is mock_cls .return_value
9898
99+ @pytest .mark .parametrize (
100+ "missing_value" ,
101+ [
102+ pytest .param ("none" , id = "bare-none" ),
103+ pytest .param ("null" , id = "bare-null" ),
104+ pytest .param ("" , id = "empty" ),
105+ pytest .param (" None " , id = "whitespace-None" ),
106+ pytest .param (" " , id = "whitespace-only" ),
107+ pytest .param (" null " , id = "whitespace-null" ),
108+ pytest .param (None , id = "python-None" ),
109+ ],
110+ )
111+ def test_namespace_args_falls_back_to_checkpoint_filename_when_pretrain_weights_missing (
112+ self , tmp_path : Path , missing_value : str | None
113+ ) -> None :
114+ """Namespace args: filename fallback fires when pretrain_weights is unset-like."""
115+ ckpt = _ns (missing_value ) # type: ignore[arg-type]
116+ _ , mock_cls = _call_from_checkpoint (ckpt , tmp_path / "rf-detr-small.pth" , "rfdetr.variants.RFDETRSmall" )
117+ mock_cls .assert_called_once ()
118+ assert mock_cls .call_args .kwargs ["num_classes" ] == 80
119+
99120
100121# ---------------------------------------------------------------------------
101122# Dict args (PTL / converted checkpoints)
@@ -151,6 +172,21 @@ def test_characterization_unknown_pretrain_weights_raises_value_error(self, tmp_
151172 with pytest .raises (ValueError , match = "Could not infer model class" ):
152173 RFDETR .from_checkpoint (tmp_path / "ckpt.pth" )
153174
175+ def test_filename_fallback_unrecognized_name_raises_value_error (self , tmp_path : Path ) -> None :
176+ """ValueError fires via filename-fallback path when filename has no known model token."""
177+ ckpt = {"args" : {"pretrain_weights" : "none" , "num_classes" : 80 }}
178+ with patch ("rfdetr.detr.torch.load" , return_value = ckpt ):
179+ with pytest .raises (ValueError , match = "Could not infer model class" ):
180+ RFDETR .from_checkpoint (tmp_path / "finetuned.pth" )
181+
182+ @pytest .mark .skipif (_IS_RFDETR_PLUS_AVAILABLE , reason = "rfdetr_plus is installed — guard not active" )
183+ def test_filename_fallback_xlarge_without_plus_raises_import_error (self , tmp_path : Path ) -> None :
184+ """ImportError fires via filename-fallback path when rfdetr_plus is absent."""
185+ ckpt = {"args" : {"pretrain_weights" : "none" , "num_classes" : 80 }}
186+ with patch ("rfdetr.detr.torch.load" , return_value = ckpt ):
187+ with pytest .raises (ImportError ):
188+ RFDETR .from_checkpoint (tmp_path / "rf-detr-xlarge-starter.pth" )
189+
154190 def test_characterization_missing_args_key_raises_key_error (self , tmp_path : Path ) -> None :
155191 """Checkpoint without 'args' key raises KeyError."""
156192 ckpt = {"model" : {}}
@@ -314,6 +350,27 @@ def test_falls_back_to_pretrain_weights_without_model_name(self, tmp_path: Path)
314350 _ , mock_cls = _call_from_checkpoint (ckpt , tmp_path / "ckpt.pth" , "rfdetr.variants.RFDETRSmall" )
315351 mock_cls .assert_called_once ()
316352
353+ @pytest .mark .parametrize (
354+ "missing_value" ,
355+ [
356+ pytest .param ("none" , id = "bare-none" ),
357+ pytest .param ("null" , id = "bare-null" ),
358+ pytest .param ("" , id = "empty" ),
359+ pytest .param (" None " , id = "whitespace-None" ),
360+ pytest .param (" " , id = "whitespace-only" ),
361+ pytest .param (" null " , id = "whitespace-null" ),
362+ pytest .param (None , id = "python-None" ),
363+ ],
364+ )
365+ def test_falls_back_to_checkpoint_filename_when_pretrain_weights_missing (
366+ self , tmp_path : Path , missing_value : str | None
367+ ) -> None :
368+ """When pretrain_weights is missing-like, from_checkpoint infers class from checkpoint filename."""
369+ ckpt = {"args" : {"pretrain_weights" : missing_value , "num_classes" : 80 }}
370+ _ , mock_cls = _call_from_checkpoint (ckpt , tmp_path / "rf-detr-small.pth" , "rfdetr.variants.RFDETRSmall" )
371+ mock_cls .assert_called_once ()
372+ assert mock_cls .call_args .kwargs ["num_classes" ] == 80
373+
317374 def test_unknown_model_name_falls_back_to_pretrain_weights (self , tmp_path : Path ) -> None :
318375 """Unrecognised model_name falls back to pretrain_weights parsing."""
319376 ckpt = {
0 commit comments