Skip to content

Commit fb96b4f

Browse files
authored
Bump min DVC version to 2.55.0 (live metrics for experiments running outside the workspace) (#3665)
* wrap all loose test data in test data generator * add new type * duplicate required functions but use new data * update test fixtures * deduplicate functions * remove checkpoints model and file system watcher (#3684) * extend timeout of run experiment test (e2e) (#3713) * prevent plotting of running experiments (#3712) * trigger plot updates whenever commit data changes (#3715) * update demo project and min required version of DVC * fix experiment id for commits (shown in plots) (#3724)
1 parent dcbded5 commit fb96b4f

File tree

112 files changed

+17506
-19940
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+17506
-19940
lines changed

demo

Submodule demo updated from 48086f1 to a9b32d1

extension/src/cli/dvc/contract.ts

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Plot } from '../../plots/webview/contract'
22

3-
export const MIN_CLI_VERSION = '2.52.0'
4-
export const LATEST_TESTED_CLI_VERSION = '2.54.0'
3+
export const MIN_CLI_VERSION = '2.55.0'
4+
export const LATEST_TESTED_CLI_VERSION = '2.55.0'
55
export const MAX_CLI_VERSION = '3'
66

77
type ErrorContents = { type: string; msg: string }
@@ -26,76 +26,92 @@ export type DataStatusOutput = {
2626
type SingleValue = string | number | boolean | null
2727
export type Value = SingleValue | SingleValue[]
2828

29-
export interface ValueTreeOrError {
30-
data?: ValueTree
31-
error?: ErrorContents
32-
}
33-
3429
type RelPathObject<T> = {
3530
[relPath: string]: T
3631
}
3732

38-
export type ValueTreeRoot = RelPathObject<ValueTreeOrError>
39-
40-
export interface ValueTreeNode {
33+
export type ValueTree = {
4134
[key: string]: Value | ValueTree
4235
}
4336

44-
export type ValueTree = ValueTreeRoot | ValueTreeNode
45-
4637
export const isValueTree = (
4738
value: Value | ValueTree
4839
): value is NonNullable<ValueTree> =>
4940
!!(value && !Array.isArray(value) && typeof value === 'object')
5041

5142
export enum ExperimentStatus {
52-
FAILED = 'Failed',
53-
QUEUED = 'Queued',
54-
RUNNING = 'Running',
55-
SUCCESS = 'Success'
43+
FAILED = 'failed',
44+
QUEUED = 'queued',
45+
RUNNING = 'running',
46+
SUCCESS = 'success'
5647
}
5748

58-
export const EXPERIMENT_WORKSPACE_ID = 'workspace'
59-
60-
export interface BaseExperimentFields {
61-
name?: string
62-
timestamp?: string | null
63-
status?: ExperimentStatus
64-
executor?: string | null
65-
checkpoint_tip?: string
66-
checkpoint_parent?: string
67-
}
49+
export const EXPERIMENT_WORKSPACE_ID = 'workspace' as const
6850

6951
type Dep = { hash: null | string; size: null | number; nfiles: null | number }
7052
type Out = Dep & { use_cache: boolean; is_data_source: boolean }
7153

54+
type Outs = RelPathObject<Out>
7255
export type Deps = RelPathObject<Dep>
7356

74-
export interface ExperimentFields extends BaseExperimentFields {
75-
params?: ValueTreeRoot
76-
metrics?: ValueTreeRoot
77-
deps?: Deps
78-
outs?: RelPathObject<Out>
79-
error?: ErrorContents
57+
export type FileDataOrError = { data: ValueTree } | DvcError
58+
export type MetricsOrParams = RelPathObject<FileDataOrError>
59+
60+
export const fileHasError = (file: FileDataOrError): file is DvcError =>
61+
!!(file as DvcError).error
62+
63+
export type ExpData = {
64+
rev: string
65+
timestamp: string | null
66+
params: MetricsOrParams | null
67+
metrics: MetricsOrParams | null
68+
deps: Deps | null
69+
outs: Outs | null
70+
meta: { has_checkpoints: boolean }
8071
}
8172

82-
export interface ExperimentFieldsOrError {
83-
data?: ExperimentFields
84-
error?: ErrorContents
73+
export enum Executor {
74+
DVC_TASK = 'dvc-task',
75+
WORKSPACE = 'workspace'
8576
}
8677

87-
export interface ExperimentsCommitOutput {
88-
[sha: string]: ExperimentFieldsOrError
89-
baseline: ExperimentFieldsOrError
78+
export type ExecutorState = {
79+
state: ExperimentStatus
80+
name: Executor | null
81+
local: {
82+
root: string | null
83+
log: string | null
84+
pid: number | null
85+
task_id?: string
86+
returncode: null | number
87+
} | null
88+
} | null
89+
90+
export type ExpWithError = {
91+
rev: string
92+
name?: string
93+
} & DvcError
94+
95+
type ExpWithData = {
96+
rev: string
97+
name?: string
98+
data: ExpData
9099
}
91100

92-
export interface ExperimentsOutput {
93-
[name: string]: ExperimentsCommitOutput
94-
[EXPERIMENT_WORKSPACE_ID]: {
95-
baseline: ExperimentFieldsOrError
96-
}
101+
export type ExpState = ExpWithData | ExpWithError
102+
103+
export type ExpRange = {
104+
revs: ExpState[]
105+
name?: string
106+
executor: ExecutorState
97107
}
98108

109+
export const experimentHasError = (
110+
expState: ExpState
111+
): expState is ExpWithError => !!(expState as { error?: unknown }).error
112+
113+
export type ExpShowOutput = (ExpState & { experiments?: ExpRange[] | null })[]
114+
99115
export interface PlotsData {
100116
[path: string]: Plot[]
101117
}

extension/src/cli/dvc/reader.test.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,23 +94,22 @@ describe('CliReader', () => {
9494
})
9595

9696
const cliOutput = await dvcReader.expShow(cwd)
97-
expect(cliOutput).toStrictEqual({
98-
[EXPERIMENT_WORKSPACE_ID]: {
99-
baseline: { error: { msg: unexpectedStderr, type: 'Caught error' } }
97+
expect(cliOutput).toStrictEqual([
98+
{
99+
error: { msg: unexpectedStderr, type: 'Caught error' },
100+
rev: EXPERIMENT_WORKSPACE_ID
100101
}
101-
})
102+
])
102103
})
103104

104-
it('should return the default output if the cli returns an empty object (no commits)', async () => {
105+
it('should return the default output if the cli returns an empty array (no commits)', async () => {
105106
const cwd = __dirname
106107
mockedCreateProcess.mockReturnValueOnce(
107-
getMockedProcess(JSON.stringify({}))
108+
getMockedProcess(JSON.stringify([]))
108109
)
109110

110111
const cliOutput = await dvcReader.expShow(cwd)
111-
expect(cliOutput).toStrictEqual({
112-
[EXPERIMENT_WORKSPACE_ID]: { baseline: {} }
113-
})
112+
expect(cliOutput).toStrictEqual([{ rev: EXPERIMENT_WORKSPACE_ID }])
114113
})
115114
})
116115

extension/src/cli/dvc/reader.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import {
1111
import {
1212
DataStatusOutput,
1313
DvcError,
14-
ExperimentsOutput,
1514
EXPERIMENT_WORKSPACE_ID,
1615
PlotsOutput,
1716
PlotsOutputOrError,
18-
RawPlotsOutput
17+
RawPlotsOutput,
18+
ExpShowOutput
1919
} from './contract'
2020
import { getOptions } from './options'
2121
import { typeCheckCommands } from '..'
@@ -24,12 +24,8 @@ import { Logger } from '../../common/logger'
2424
import { parseNonStandardJson } from '../../util/json'
2525
import { definedAndNonEmpty } from '../../util/array'
2626

27-
const defaultExperimentsOutput: ExperimentsOutput = {
28-
[EXPERIMENT_WORKSPACE_ID]: { baseline: {} }
29-
}
30-
3127
export const isDvcError = <
32-
T extends ExperimentsOutput | DataStatusOutput | RawPlotsOutput
28+
T extends ExpShowOutput | DataStatusOutput | RawPlotsOutput
3329
>(
3430
dataOrError: T | DvcError
3531
): dataOrError is DvcError =>
@@ -68,19 +64,17 @@ export class DvcReader extends DvcCli {
6864
public async expShow(
6965
cwd: string,
7066
...flags: (ExperimentFlag | string)[]
71-
): Promise<ExperimentsOutput> {
72-
const output = await this.readProcess<ExperimentsOutput>(
67+
): Promise<ExpShowOutput> {
68+
const output = await this.readProcess<ExpShowOutput>(
7369
cwd,
74-
JSON.stringify(defaultExperimentsOutput),
70+
JSON.stringify([]),
7571
Command.EXPERIMENT,
7672
SubCommand.SHOW,
7773
...flags,
7874
Flag.JSON
7975
)
8076
if (isDvcError(output) || isEmpty(output)) {
81-
return {
82-
[EXPERIMENT_WORKSPACE_ID]: { baseline: output as DvcError | {} }
83-
}
77+
return [{ rev: EXPERIMENT_WORKSPACE_ID, ...(output as DvcError) }]
8478
}
8579
return output
8680
}
@@ -150,7 +144,7 @@ export class DvcReader extends DvcCli {
150144
}
151145

152146
private async readProcess<
153-
T extends DataStatusOutput | ExperimentsOutput | RawPlotsOutput
147+
T extends DataStatusOutput | ExpShowOutput | RawPlotsOutput
154148
>(cwd: string, defaultValue: string, ...args: Args): Promise<T | DvcError> {
155149
try {
156150
const output =

extension/src/cli/dvc/viewer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ export class DvcViewer extends Disposable implements ICli {
5151
return this.createProcess(name, cwd, args)
5252
}
5353

54-
public queueLogs(cwd: string, expName: string) {
54+
public queueLogs(cwd: string, id: string) {
5555
return this.run(
56-
`${expName} logs`,
56+
`${id} logs`,
5757
cwd,
5858
Command.QUEUE,
5959
QueueSubCommand.LOGS,
60-
expName,
60+
id,
6161
Flag.FOLLOW
6262
)
6363
}

extension/src/data/index.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ import { getRelativePattern } from '../fileSystem/relativePattern'
44
import { createFileSystemWatcher } from '../fileSystem/watcher'
55
import { ProcessManager } from '../process/manager'
66
import { InternalCommands } from '../commands/internal'
7-
import { ExperimentsOutput, PlotsOutputOrError } from '../cli/dvc/contract'
7+
import { ExpShowOutput, PlotsOutputOrError } from '../cli/dvc/contract'
88
import { uniqueValues } from '../util/array'
99
import { DeferredDisposable } from '../class/deferred'
1010
import { isSameOrChild } from '../fileSystem'
1111

1212
export abstract class BaseData<
13-
T extends { data: PlotsOutputOrError; revs: string[] } | ExperimentsOutput
13+
T extends { data: PlotsOutputOrError; revs: string[] } | ExpShowOutput
1414
> extends DeferredDisposable {
1515
public readonly onDidUpdate: Event<T>
16+
public readonly onDidChangeDvcYaml: Event<void>
1617

1718
protected readonly dvcRoot: string
1819
protected readonly processManager: ProcessManager
@@ -25,6 +26,10 @@ export abstract class BaseData<
2526
new EventEmitter()
2627
)
2728

29+
private readonly dvcYamlChanged: EventEmitter<void> = this.dispose.track(
30+
new EventEmitter<void>()
31+
)
32+
2833
constructor(
2934
dvcRoot: string,
3035
internalCommands: InternalCommands,
@@ -42,6 +47,8 @@ export abstract class BaseData<
4247
this.onDidUpdate = this.updated.event
4348
this.staticFiles = staticFiles
4449

50+
this.onDidChangeDvcYaml = this.dvcYamlChanged.event
51+
4552
this.watchFiles()
4653

4754
this.waitForInitialData()
@@ -80,6 +87,10 @@ export abstract class BaseData<
8087
) {
8188
void this.managedUpdate(path)
8289
}
90+
91+
if (path.endsWith('dvc.yaml')) {
92+
this.dvcYamlChanged.fire()
93+
}
8394
}
8495
)
8596
}

0 commit comments

Comments
 (0)