@@ -196,13 +196,36 @@ def get_rdict(left, right=None, for_cancel_broadcast=False):
196196 upg (
197197 {'runtime' : {'__MANY__' : rdict }},
198198 'test' ,
199- for_cancel_broadcast = for_cancel_broadcast ,
199+ broadcast = 'cancel' if for_cancel_broadcast else True ,
200200 )
201+ rdict = strip_empty_sections (rdict )
201202 # Perform validation, but don't coerce the original (deepcopy).
202203 cylc_config_validate (deepcopy (rdict ), SPEC ['runtime' ]['__MANY__' ])
203204 return rdict
204205
205206
207+ def strip_empty_sections (data ):
208+ """Recursively strip data structure of empty dicts.
209+
210+ This is needed post-upgrade as the upgrader can leave empty sections
211+ behind.
212+
213+ >>> strip_empty_sections(
214+ ... {'job': {}, 'thing limit': 'PT2S', 'whatever': ''})
215+ {'thing limit': 'PT2S', 'whatever': ''}
216+
217+ >>> strip_empty_sections({'section': {'subsection': {}}})
218+ {}
219+ """
220+ if not isinstance (data , dict ):
221+ return data
222+ return {
223+ key : stripped
224+ for key , val in data .items ()
225+ if (stripped := strip_empty_sections (val )) != {}
226+ }
227+
228+
206229def files_to_settings (settings , setting_files , cancel_mode = False ):
207230 """Parse setting files, and append to settings."""
208231 cfg = ParsecConfig (
@@ -437,9 +460,11 @@ async def run(options: 'Values', workflow_id):
437460 raise InputError (
438461 "--cancel=[SEC]ITEM does not take a value" )
439462 option_item = option_item .strip ()
440- setting = get_rdict (option_item , for_cancel_broadcast = True )
441- settings .append (setting )
463+ if setting : = get_rdict (option_item , for_cancel_broadcast = True ):
464+ settings .append (setting )
442465 files_to_settings (settings , options .cancel_files , options .cancel )
466+ if not settings :
467+ raise InputError ("No valid settings to broadcast." )
443468 mutation_kwargs ['variables' ].update (
444469 {
445470 'bMode' : 'Clear' ,
@@ -456,9 +481,11 @@ async def run(options: 'Values', workflow_id):
456481 raise InputError (
457482 "--set=[SEC]ITEM=VALUE requires a value" )
458483 lhs , rhs = [s .strip () for s in option_item .split ("=" , 1 )]
459- setting = get_rdict (lhs , rhs )
460- settings .append (setting )
484+ if setting : = get_rdict (lhs , rhs ):
485+ settings .append (setting )
461486 files_to_settings (settings , options .setting_files )
487+ if not settings :
488+ raise InputError ("No valid settings to broadcast." )
462489 mutation_kwargs ['variables' ].update (
463490 {
464491 'bMode' : 'Set' ,
@@ -472,9 +499,9 @@ async def run(options: 'Values', workflow_id):
472499
473500 results = await pclient .async_request ('graphql' , mutation_kwargs )
474501 try :
502+ bad_options = {}
475503 for result in results ['broadcast' ]['result' ]:
476- modified_settings = result ['response' ][0 ]
477- bad_options = result ['response' ][1 ]
504+ modified_settings , bad_options = result ['response' ]
478505 if modified_settings :
479506 ret ['stdout' ].append (
480507 get_broadcast_change_report (
@@ -483,7 +510,7 @@ async def run(options: 'Values', workflow_id):
483510 )
484511 )
485512 bad_result = report_bad_options (bad_options , is_set = report_set )
486- except TypeError :
513+ except ( TypeError , ValueError ) :
487514 # Catch internal API server errors
488515 bad_result = cparse (f'<red>{ results } </red>' )
489516
0 commit comments