@@ -645,6 +645,146 @@ def test_cached_batch_size_does_not_override_changed_dataset_value(self):
645645 self .assertEqual (backend ["train_batch_size" ], 4 )
646646 self .assertEqual (result ["config" ]["train_batch_size" ], 4 )
647647
648+ def test_cached_runtime_config_does_not_override_live_values (self ):
649+ from simpletuner .helpers .data_backend .factory import FactoryRegistry , init_backend_config
650+
651+ self .args .train_batch_size = 8
652+ backend = {
653+ "id" : "image-runtime-config" ,
654+ "type" : "local" ,
655+ "dataset_type" : "image" ,
656+ "instance_data_dir" : self .temp_dir ,
657+ "train_batch_size" : 4 ,
658+ "repeats" : 2 ,
659+ "start_epoch" : 3 ,
660+ "start_step" : 12000 ,
661+ "end_epoch" : 6 ,
662+ "end_step" : 24000 ,
663+ }
664+ init_backend = init_backend_config (backend , self .args , self .accelerator )
665+ expected_runtime_config = {
666+ key : init_backend ["config" ][key ]
667+ for key in ("train_batch_size" , "repeats" , "start_epoch" , "start_step" , "end_epoch" , "end_step" )
668+ }
669+ metadata_backend = MagicMock ()
670+ metadata_backend .config = {
671+ "train_batch_size" : 1 ,
672+ "repeats" : 0 ,
673+ "start_epoch" : 1 ,
674+ "start_step" : 0 ,
675+ "end_epoch" : None ,
676+ "end_step" : None ,
677+ }
678+ metadata_backend .__len__ .return_value = 1
679+ init_backend ["metadata_backend" ] = metadata_backend
680+
681+ factory = FactoryRegistry (
682+ args = self .args ,
683+ accelerator = self .accelerator ,
684+ text_encoders = self .text_encoders ,
685+ tokenizers = self .tokenizers ,
686+ model = self .model ,
687+ )
688+ with patch ("simpletuner.helpers.data_backend.factory.StateTracker.set_data_backend_config" ):
689+ factory ._handle_config_versioning (backend , init_backend )
690+
691+ self .assertEqual (
692+ {key : init_backend ["config" ][key ] for key in expected_runtime_config },
693+ expected_runtime_config ,
694+ )
695+ self .assertEqual (
696+ {key : metadata_backend .config [key ] for key in expected_runtime_config },
697+ expected_runtime_config ,
698+ )
699+ self .assertEqual (
700+ {key : backend [key ] for key in expected_runtime_config },
701+ expected_runtime_config ,
702+ )
703+
704+ def test_cached_runtime_defaults_are_removed_when_absent_from_live_config (self ):
705+ from simpletuner .helpers .data_backend .factory import FactoryRegistry , init_backend_config
706+
707+ backend = {
708+ "id" : "image-runtime-defaults" ,
709+ "type" : "local" ,
710+ "dataset_type" : "image" ,
711+ "instance_data_dir" : self .temp_dir ,
712+ }
713+ init_backend = init_backend_config (backend , self .args , self .accelerator )
714+ metadata_backend = MagicMock ()
715+ metadata_backend .config = {
716+ "repeats" : 4 ,
717+ "end_epoch" : 8 ,
718+ "end_step" : 16000 ,
719+ }
720+ metadata_backend .__len__ .return_value = 1
721+ init_backend ["metadata_backend" ] = metadata_backend
722+
723+ factory = FactoryRegistry (
724+ args = self .args ,
725+ accelerator = self .accelerator ,
726+ text_encoders = self .text_encoders ,
727+ tokenizers = self .tokenizers ,
728+ model = self .model ,
729+ )
730+ with patch ("simpletuner.helpers.data_backend.factory.StateTracker.set_data_backend_config" ):
731+ factory ._handle_config_versioning (backend , init_backend )
732+
733+ self .assertNotIn ("repeats" , init_backend ["config" ])
734+ self .assertIsNone (init_backend ["config" ]["end_epoch" ])
735+ self .assertIsNone (init_backend ["config" ]["end_step" ])
736+ self .assertNotIn ("repeats" , metadata_backend .config )
737+ self .assertIsNone (metadata_backend .config ["end_epoch" ])
738+ self .assertIsNone (metadata_backend .config ["end_step" ])
739+
740+ def test_metadata_cache_reload_does_not_leave_stale_runtime_config_active (self ):
741+ from simpletuner .helpers .data_backend .factory import FactoryRegistry , init_backend_config
742+
743+ backend = {
744+ "id" : "image-runtime-reload" ,
745+ "type" : "local" ,
746+ "dataset_type" : "image" ,
747+ "instance_data_dir" : self .temp_dir ,
748+ "repeats" : 3 ,
749+ "start_step" : 12000 ,
750+ }
751+ init_backend = init_backend_config (backend , self .args , self .accelerator )
752+ init_backend ["data_backend" ] = MagicMock (id = backend ["id" ])
753+ init_backend ["instance_data_dir" ] = backend ["instance_data_dir" ]
754+ live_config = init_backend ["config" ].copy ()
755+ observed_configs = []
756+
757+ def set_config (data_backend_id , config ):
758+ self .assertEqual (data_backend_id , backend ["id" ])
759+ observed_configs .append (config .copy ())
760+
761+ def create_metadata_backend (** kwargs ):
762+ set_config (backend ["id" ], {** live_config , "repeats" : 0 , "start_step" : 0 })
763+ metadata_backend = MagicMock ()
764+ metadata_backend .aspect_ratio_bucket_indices = {}
765+ return metadata_backend
766+
767+ factory = FactoryRegistry (
768+ args = self .args ,
769+ accelerator = self .accelerator ,
770+ text_encoders = self .text_encoders ,
771+ tokenizers = self .tokenizers ,
772+ model = self .model ,
773+ )
774+ with (
775+ patch (
776+ "simpletuner.helpers.metadata.backends.discovery.DiscoveryMetadataBackend" ,
777+ side_effect = create_metadata_backend ,
778+ ),
779+ patch (
780+ "simpletuner.helpers.data_backend.factory.StateTracker.set_data_backend_config" ,
781+ side_effect = set_config ,
782+ ),
783+ ):
784+ factory ._configure_metadata_backend (backend , init_backend )
785+
786+ self .assertEqual (observed_configs [- 1 ], live_config )
787+
648788 def test_inline_conditioning_auto_generation_for_image_dataset (self ):
649789 """Inline conditioning blocks on image datasets should spawn auto-generated conditioning datasets."""
650790 from simpletuner .helpers .data_backend .factory import FactoryRegistry
0 commit comments