Skip to content

Commit 17cab9a

Browse files
authored
Add experiment run reset to menus (#1719)
* add run reset experiment everywhere * hoist remove in context menu * reorder context menu * always have run reset in the context menu
1 parent 31b7a01 commit 17cab9a

File tree

12 files changed

+223
-30
lines changed

12 files changed

+223
-30
lines changed

extension/package.json

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,15 @@
238238
"dark": "resources/dark/run-experiment.svg"
239239
}
240240
},
241+
{
242+
"title": "%command.modifyExperimentParamsResetAndRun%",
243+
"command": "dvc.modifyExperimentParamsResetAndRun",
244+
"category": "DVC",
245+
"icon": {
246+
"light": "resources/light/run-experiment.svg",
247+
"dark": "resources/dark/run-experiment.svg"
248+
}
249+
},
241250
{
242251
"title": "%command.queueExperiment%",
243252
"command": "dvc.queueExperiment",
@@ -415,6 +424,15 @@
415424
"dark": "resources/dark/run-experiment.svg"
416425
}
417426
},
427+
{
428+
"title": "%command.views.experimentsTree.resetRunExperiment%",
429+
"command": "dvc.views.experimentsTree.resetRunExperiment",
430+
"category": "DVC",
431+
"icon": {
432+
"light": "resources/light/run-experiment.svg",
433+
"dark": "resources/dark/run-experiment.svg"
434+
}
435+
},
418436
{
419437
"title": "%command.views.experimentsTree.selectExperiments%",
420438
"command": "dvc.views.experimentsTree.selectExperiments",
@@ -508,11 +526,11 @@
508526
},
509527
{
510528
"command": "dvc.applyExperiment",
511-
"when": "dvc.commands.available && dvc.project.available"
529+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
512530
},
513531
{
514532
"command": "dvc.branchExperiment",
515-
"when": "dvc.commands.available && dvc.project.available"
533+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
516534
},
517535
{
518536
"command": "dvc.checkout",
@@ -552,7 +570,7 @@
552570
},
553571
{
554572
"command": "dvc.experimentGarbageCollect",
555-
"when": "dvc.commands.available && dvc.project.available"
573+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
556574
},
557575
{
558576
"command": "dvc.findInFolder",
@@ -596,23 +614,27 @@
596614
},
597615
{
598616
"command": "dvc.modifyExperimentParamsAndQueue",
599-
"when": "dvc.commands.available && dvc.project.available"
617+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
600618
},
601619
{
602620
"command": "dvc.modifyExperimentParamsAndRun",
603-
"when": "dvc.commands.available && dvc.project.available"
621+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
622+
},
623+
{
624+
"command": "dvc.modifyExperimentParamsResetAndRun",
625+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
604626
},
605627
{
606628
"command": "dvc.queueExperiment",
607-
"when": "dvc.commands.available && dvc.project.available"
629+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
608630
},
609631
{
610632
"command": "dvc.removeExperiment",
611-
"when": "dvc.commands.available && dvc.project.available"
633+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
612634
},
613635
{
614636
"command": "dvc.removeExperimentQueue",
615-
"when": "dvc.commands.available && dvc.project.available"
637+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
616638
},
617639
{
618640
"command": "dvc.removeExperimentsTableFilters",
@@ -624,7 +646,7 @@
624646
},
625647
{
626648
"command": "dvc.removeQueuedExperiment",
627-
"when": "dvc.commands.available && dvc.project.available"
649+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
628650
},
629651
{
630652
"command": "dvc.removeTarget",
@@ -640,15 +662,15 @@
640662
},
641663
{
642664
"command": "dvc.runExperiment",
643-
"when": "dvc.commands.available && dvc.project.available"
665+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
644666
},
645667
{
646668
"command": "dvc.runQueuedExperiments",
647-
"when": "dvc.commands.available && dvc.project.available"
669+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
648670
},
649671
{
650672
"command": "dvc.runResetExperiment",
651-
"when": "dvc.commands.available && dvc.project.available"
673+
"when": "dvc.commands.available && dvc.project.available && !dvc.runner.running"
652674
},
653675
{
654676
"command": "dvc.selectForCompare",
@@ -959,10 +981,15 @@
959981
"when": "view == dvc.views.experimentsTree && dvc.commands.available && viewItem =~ /^(workspace|branch|experiment|queued)$/ && !dvc.runner.running"
960982
},
961983
{
962-
"command": "dvc.views.experimentsTree.queueExperiment",
984+
"command": "dvc.views.experimentsTree.resetRunExperiment",
963985
"group": "1_do@2",
964986
"when": "view == dvc.views.experimentsTree && dvc.commands.available && viewItem =~ /^(workspace|branch|experiment|queued)$/ && !dvc.runner.running"
965987
},
988+
{
989+
"command": "dvc.views.experimentsTree.queueExperiment",
990+
"group": "1_do@3",
991+
"when": "view == dvc.views.experimentsTree && dvc.commands.available && viewItem =~ /^(workspace|branch|experiment|queued)$/ && !dvc.runner.running"
992+
},
966993
{
967994
"command": "dvc.views.experimentsTree.selectExperiments",
968995
"group": "inline",
@@ -1007,14 +1034,29 @@
10071034
},
10081035
{
10091036
"command": "dvc.runExperiment",
1010-
"when": "view == dvc.views.experimentsTree && !dvc.experiments.webviewActive",
1037+
"when": "view == dvc.views.experimentsTree && !dvc.experiments.webviewActive && !dvc.runner.running",
10111038
"group": "1_run@1"
10121039
},
10131040
{
10141041
"command": "dvc.runExperiment",
1015-
"when": "view == dvc.views.experimentsTree && dvc.experiments.webviewActive",
1042+
"when": "view == dvc.views.experimentsTree && dvc.experiments.webviewActive && !dvc.runner.running",
1043+
"group": "navigation@1"
1044+
},
1045+
{
1046+
"command": "dvc.stopRunningExperiment",
1047+
"when": "view == dvc.views.experimentsTree && !dvc.experiments.webviewActive && dvc.runner.running",
1048+
"group": "1_run@1"
1049+
},
1050+
{
1051+
"command": "dvc.stopRunningExperiment",
1052+
"when": "view == dvc.views.experimentsTree && dvc.experiments.webviewActive && dvc.runner.running",
10161053
"group": "navigation@1"
10171054
},
1055+
{
1056+
"command": "dvc.runResetExperiment",
1057+
"when": "view == dvc.views.experimentsTree && !dvc.runner.running",
1058+
"group": "1_run@2"
1059+
},
10181060
{
10191061
"command": "dvc.showPlots",
10201062
"when": "view == dvc.views.experimentsTree && !dvc.plots.webviewActive",
@@ -1028,17 +1070,27 @@
10281070
{
10291071
"command": "dvc.runQueuedExperiments",
10301072
"when": "view == dvc.views.experimentsTree && !dvc.runner.running",
1031-
"group": "1_run@2"
1073+
"group": "1_run@3"
10321074
},
10331075
{
1034-
"command": "dvc.queueExperiment",
1076+
"command": "dvc.modifyExperimentParamsAndRun",
10351077
"when": "view == dvc.views.experimentsTree && !dvc.runner.running",
1036-
"group": "2_queue@1"
1078+
"group": "2_modify@1"
1079+
},
1080+
{
1081+
"command": "dvc.modifyExperimentParamsResetAndRun",
1082+
"when": "view == dvc.views.experimentsTree && !dvc.runner.running",
1083+
"group": "2_modify@2"
10371084
},
10381085
{
10391086
"command": "dvc.modifyExperimentParamsAndQueue",
10401087
"when": "view == dvc.views.experimentsTree && !dvc.runner.running",
1041-
"group": "2_queue@2"
1088+
"group": "2_modify@3"
1089+
},
1090+
{
1091+
"command": "dvc.queueExperiment",
1092+
"when": "view == dvc.views.experimentsTree && !dvc.runner.running",
1093+
"group": "3_queue@1"
10421094
},
10431095
{
10441096
"command": "dvc.views.experimentsTree.autoApplyFilters",

extension/package.nls.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"command.pushTarget": "Push",
3131
"command.modifyExperimentParamsAndQueue": "Modify Experiment Param(s) and Queue",
3232
"command.modifyExperimentParamsAndRun": "Modify Experiment Param(s) and Run",
33+
"command.modifyExperimentParamsResetAndRun": "Modify Experiment Param(s) Reset and Run",
3334
"command.queueExperiment": "Queue Experiment",
3435
"command.removeExperiment": "Remove Experiment",
3536
"command.removeExperimentQueue": "Remove All Queued Experiments",
@@ -60,6 +61,7 @@
6061
"command.views.experimentsTree.queueExperiment": "Modify Param(s) and Queue",
6162
"command.views.experimentsTree.removeExperiment": "Remove",
6263
"command.views.experimentsTree.runExperiment": "Modify Param(s) and Run",
64+
"command.views.experimentsTree.resetRunExperiment": "Modify Param(s) Reset and Run",
6365
"command.views.experimentsTree.selectExperiments": "Select Experiments to Display in Plots",
6466
"command.views.plotsPathsTree.selectPlots": "Select Plots to Display",
6567
"config.doNotRecommendRedHatExtension.description": "Do not prompt to install the Red Hat YAML extension to assist with DVC YAML schema validation.",

extension/src/commands/external.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export enum RegisteredCommands {
3737
EXPERIMENT_TREE_QUEUE = 'dvc.views.experimentsTree.queueExperiment',
3838
EXPERIMENT_TREE_REMOVE = 'dvc.views.experimentsTree.removeExperiment',
3939
EXPERIMENT_TREE_RUN = 'dvc.views.experimentsTree.runExperiment',
40+
EXPERIMENT_TREE_RUN_RESET = 'dvc.views.experimentsTree.resetRunExperiment',
4041
EXPERIMENT_SELECT = 'dvc.views.experimentsTree.selectExperiments',
4142
EXPERIMENT_SHOW = 'dvc.showExperiments',
4243
EXPERIMENT_SORT_ADD = 'dvc.addExperimentsTableSort',
@@ -46,6 +47,7 @@ export enum RegisteredCommands {
4647
EXPERIMENT_TOGGLE = 'dvc.views.experimentsTree.toggleStatus',
4748
MODIFY_EXPERIMENT_PARAMS_AND_QUEUE = 'dvc.modifyExperimentParamsAndQueue',
4849
MODIFY_EXPERIMENT_PARAMS_AND_RUN = 'dvc.modifyExperimentParamsAndRun',
50+
MODIFY_EXPERIMENT_PARAMS_RESET_AND_RUN = 'dvc.modifyExperimentParamsResetAndRun',
4951
STOP_EXPERIMENT = 'dvc.stopRunningExperiment',
5052

5153
PLOTS_PATH_TOGGLE = 'dvc.views.plotsPathsTree.toggleStatus',

extension/src/experiments/commands/register.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ const registerExperimentCwdCommands = (
3939
)
4040
)
4141

42+
internalCommands.registerExternalCommand(
43+
RegisteredCommands.MODIFY_EXPERIMENT_PARAMS_RESET_AND_RUN,
44+
() =>
45+
experiments.pauseUpdatesThenRun(() =>
46+
experiments.modifyExperimentParamsAndRun(
47+
AvailableCommands.EXPERIMENT_RUN_RESET
48+
)
49+
)
50+
)
51+
4252
internalCommands.registerExternalCliCommand(
4353
RegisteredCliCommands.EXPERIMENT_REMOVE_QUEUE,
4454
() =>

extension/src/experiments/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,12 @@ export class Experiments extends BaseRepository<TableData> {
403403
AvailableCommands.EXPERIMENT_RUN,
404404
message.payload
405405
)
406+
case MessageFromWebviewType.VARY_EXPERIMENT_PARAMS_RESET_AND_RUN:
407+
return this.modifyExperimentParamsAndRun(
408+
AvailableCommands.EXPERIMENT_RUN_RESET,
409+
message.payload
410+
)
411+
406412
case MessageFromWebviewType.REMOVE_EXPERIMENT:
407413
return this.removeExperiment(message.payload)
408414
default:

extension/src/experiments/model/tree.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,16 @@ export class ExperimentsTree
164164
)
165165
)
166166

167+
internalCommands.registerExternalCommand<ExperimentItem>(
168+
RegisteredCommands.EXPERIMENT_TREE_RUN_RESET,
169+
({ dvcRoot, id }: ExperimentItem) =>
170+
this.experiments.modifyExperimentParamsAndRun(
171+
AvailableCommands.EXPERIMENT_RUN_RESET,
172+
dvcRoot,
173+
id
174+
)
175+
)
176+
167177
internalCommands.registerExternalCommand<ExperimentItem>(
168178
RegisteredCommands.EXPERIMENT_TREE_REMOVE,
169179
({ dvcRoot, id }: ExperimentItem) =>

extension/src/telemetry/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,12 @@ export interface IEventNamePropertyMapping {
121121
[EventName.EXPERIMENT_TREE_QUEUE]: undefined
122122
[EventName.EXPERIMENT_TREE_REMOVE]: undefined
123123
[EventName.EXPERIMENT_TREE_RUN]: undefined
124+
[EventName.EXPERIMENT_TREE_RUN_RESET]: undefined
124125
[EventName.EXPERIMENT_TOGGLE]: undefined
125126
[EventName.QUEUE_EXPERIMENT]: undefined
126127
[EventName.MODIFY_EXPERIMENT_PARAMS_AND_QUEUE]: undefined
127128
[EventName.MODIFY_EXPERIMENT_PARAMS_AND_RUN]: undefined
129+
[EventName.MODIFY_EXPERIMENT_PARAMS_RESET_AND_RUN]: undefined
128130
[EventName.STOP_EXPERIMENT]: { stopped: boolean; wasRunning: boolean }
129131

130132
[EventName.PLOTS_PATH_TOGGLE]: undefined

extension/src/test/suite/experiments/index.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,38 @@ suite('Experiments Test Suite', () => {
453453
)
454454
})
455455

456+
it("should be able to handle a message to modify an experiment's params reset and run a new experiment", async () => {
457+
const { experiments, mockExecuteCommand } =
458+
setupExperimentsAndMockCommands()
459+
460+
const mockModifiedParams = [
461+
'-S',
462+
'params.yaml:lr=0.0001',
463+
'-S',
464+
'params.yaml:weight_decay=0.2'
465+
]
466+
467+
stub(experiments, 'pickAndModifyParams').resolves(mockModifiedParams)
468+
469+
const webview = await experiments.showWebview()
470+
const mockMessageReceived = getMessageReceivedEmitter(webview)
471+
const mockExperimentId = 'mock-experiment-id'
472+
const tableChangePromise = experimentsUpdatedEvent(experiments)
473+
474+
mockMessageReceived.fire({
475+
payload: mockExperimentId,
476+
type: MessageFromWebviewType.VARY_EXPERIMENT_PARAMS_RESET_AND_RUN
477+
})
478+
479+
await tableChangePromise
480+
expect(mockExecuteCommand).to.be.calledOnce
481+
expect(mockExecuteCommand).to.be.calledWithExactly(
482+
AvailableCommands.EXPERIMENT_RUN_RESET,
483+
dvcDemoPath,
484+
...mockModifiedParams
485+
)
486+
})
487+
456488
it('should be able to handle a message to remove an experiment', async () => {
457489
const { experiments, mockExecuteCommand } =
458490
setupExperimentsAndMockCommands()

extension/src/test/suite/experiments/model/tree.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,4 +580,69 @@ suite('Experiments Tree Test Suite', () => {
580580
)
581581
})
582582
})
583+
584+
it('should be able to reset and run a new experiment from an existing one with dvc.views.experimentsTree.resetRunExperiment', async () => {
585+
const baseExperimentId = 'workspace'
586+
587+
const { cliRunner, experiments, experimentsModel } =
588+
buildExperiments(disposable)
589+
590+
await experiments.isReady()
591+
592+
const mockRunExperimentReset = stub(
593+
cliRunner,
594+
'runExperimentReset'
595+
).resolves(undefined)
596+
597+
const mockGetOnlyOrPickProject = stub(
598+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
599+
(WorkspaceExperiments as any).prototype,
600+
'getOnlyOrPickProject'
601+
)
602+
stub(WorkspaceExperiments.prototype, 'getRepository').returns(experiments)
603+
604+
const getParamsSpy = spy(experimentsModel, 'getExperimentParams')
605+
606+
const mockShowQuickPick = stub(window, 'showQuickPick') as SinonStub<
607+
[items: readonly QuickPickItem[], options: QuickPickOptionsWithTitle],
608+
Thenable<QuickPickItem[] | QuickPickItemWithValue<string> | undefined>
609+
>
610+
mockShowQuickPick.resolves([
611+
{
612+
label: 'params.yaml:dropout',
613+
value: { path: 'params.yaml:dropout', value: 0.1 }
614+
},
615+
{
616+
label: 'params.yaml:process.threshold',
617+
value: { path: 'params.yaml:process.threshold', value: 0.8 }
618+
}
619+
] as QuickPickItemWithValue<Param>[])
620+
621+
stub(window, 'showInputBox')
622+
.onFirstCall()
623+
.resolves('0.11')
624+
.onSecondCall()
625+
.resolves('0.82')
626+
627+
await commands.executeCommand(
628+
RegisteredCommands.EXPERIMENT_TREE_RUN_RESET,
629+
{
630+
dvcRoot: dvcDemoPath,
631+
id: baseExperimentId
632+
}
633+
)
634+
635+
expect(mockGetOnlyOrPickProject).not.to.be.called
636+
expect(getParamsSpy).to.be.calledOnce
637+
expect(getParamsSpy).to.be.calledWithExactly(baseExperimentId)
638+
expect(mockShowQuickPick).to.be.calledOnce
639+
expect(mockRunExperimentReset).to.be.calledOnce
640+
expect(mockRunExperimentReset).to.be.calledWith(
641+
dvcDemoPath,
642+
'-S',
643+
'params.yaml:dropout=0.11',
644+
'-S',
645+
'params.yaml:process.threshold=0.82'
646+
)
647+
})
583648
})

0 commit comments

Comments
 (0)