@@ -1658,6 +1658,51 @@ def test_corrupt_paths_sp_composite_scalar_auto_heals(self):
16581658 base_path ,
16591659 )
16601660
1661+ def test_delete_all_species_jobs_preserves_sp_composite_dict (self ):
1662+ """Regression: ``delete_all_species_jobs`` rebuilds ``paths`` via a
1663+ dict-comprehension that maps every key to ``''`` (with one carve-out
1664+ for ``'irc'`` → list). That clobbers ``paths['sp_composite']`` from
1665+ ``dict[sub_label → path]`` to an empty string, and the next composite
1666+ sub-job completion crashes with
1667+ ``TypeError: 'str' object does not support item assignment``.
1668+
1669+ ``sp_composite`` must be preserved as ``dict()`` (parallel to ``irc``
1670+ being preserved as ``list()``)."""
1671+ tmp = os .path .join (self .project_directory , "fx_delete_all" )
1672+ os .makedirs (tmp , exist_ok = True )
1673+ recipe = {
1674+ "base" : {"method" : "hf" , "basis" : "cc-pVTZ" },
1675+ "corrections" : [
1676+ {"label" : "delta_T" , "type" : "delta" ,
1677+ "high" : {"method" : "ccsdt" , "basis" : "cc-pVDZ" },
1678+ "low" : {"method" : "ccsd(t)" , "basis" : "cc-pVDZ" }},
1679+ ],
1680+ }
1681+ protocol = CompositeProtocol .from_user_input (recipe )
1682+ spc = ARCSpecies (label = 'H2' , smiles = '[H][H]' )
1683+ spc .final_xyz = {'symbols' : ('H' , 'H' ),
1684+ 'coords' : ((0 , 0 , 0 ), (0 , 0 , 0.74 )),
1685+ 'isotopes' : (1 , 1 )}
1686+ sched = self ._make_scheduler ([spc ], sp_composite = protocol )
1687+ # Drive a base completion through the real path so paths['sp_composite']
1688+ # is a populated dict, not the freshly-init'd empty one.
1689+ base_path = os .path .join (tmp , "base.out" )
1690+ self ._write_gaussian_fixture (base_path , - 1.10 )
1691+ sched .post_sp_actions ('H2' , base_path , protocol .base .level )
1692+ self .assertIsInstance (sched .output ['H2' ]['paths' ]['sp_composite' ], dict )
1693+ self .assertEqual (sched .output ['H2' ]['paths' ]['sp_composite' ]['base' ], base_path )
1694+ # Now exercise the path that clobbers it. delete_all_species_jobs
1695+ # iterates self.job_dict[label] which the no-op test scheduler may
1696+ # leave empty — that's fine, the dict-comprehension at the end of
1697+ # the method runs unconditionally and is what corrupts paths.
1698+ sched .delete_all_species_jobs ('H2' )
1699+ # Contract: sp_composite stays a dict (parallel to irc staying a list).
1700+ self .assertIsInstance (sched .output ['H2' ]['paths' ]['sp_composite' ], dict )
1701+ # Next sub-job completion must not crash.
1702+ delta_T_high_path = os .path .join (tmp , "delta_T_high.out" )
1703+ self ._write_gaussian_fixture (delta_T_high_path , - 1.15 )
1704+ sched .post_sp_actions ('H2' , delta_T_high_path , protocol .corrections [0 ].high )
1705+
16611706 # --- Phase 3.5: preset name + reference preservation ------------------- #
16621707
16631708 def test_preset_name_and_reference_survive_to_notebook_section (self ):
0 commit comments