Skip to content

Commit a79e873

Browse files
authored
feat(protocol-designer): add python field to commands and timeline (#17383)
# Overview This starts the plumbing for Python generation from Protocol Designer. AUTH-1385 We're adding a field for Python code to each command (`CommandsAndWarnings`) and to each entry of the timeline (`CommandsAndRobotState`). And in the reducer, we concatenate the Python commands together, analogously to how we concatenate the JSON commands together. ## Test Plan and Hands on Testing I added unit tests to show that the Python code concatenation works, and that the Python code gets copied from the CommandCreators to the Timeline. The tests also demonstrate that the changes do NOT affect the behavior of existing commands that don't generate Python. I've also done hands-on testing in a private experimental branch that has a more complete implementation of Python generation. ## Review requests My first time making a functional change to PD, let me know if I'm overlooking anything. ## Risk assessment Low. Should not cause any observable change to PD's behavior.
1 parent 253c300 commit a79e873

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-0
lines changed

step-generation/src/__tests__/glue.test.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,30 @@ const divideCreator: any = (
9393
}
9494
}
9595

96+
const pythonHelloWorldCreator: any = (
97+
params: CountParams,
98+
invariantContext: InvariantContext,
99+
prevState: CountState
100+
) => {
101+
return {
102+
commands: [],
103+
warnings: [],
104+
python: 'print("Hello world")',
105+
}
106+
}
107+
108+
const pythonGoodbyeWorldCreator: any = (
109+
params: CountParams,
110+
invariantContext: InvariantContext,
111+
prevState: CountState
112+
) => {
113+
return {
114+
commands: [],
115+
warnings: [],
116+
python: 'print("Goodbye world")',
117+
}
118+
}
119+
96120
function mockNextRobotStateAndWarningsSingleCommand(
97121
command: CountCommand,
98122
invariantContext: any,
@@ -177,6 +201,9 @@ describe('reduceCommandCreators', () => {
177201
{ command: 'multiply', params: { value: 2 } },
178202
],
179203
warnings: [],
204+
// Note no `python` field here.
205+
// Existing CommandCreators that don't emit Python should behave exactly the same as before.
206+
// This test makes sure we do NOT produce results like `python:'undefined'` or `python:''` or `python:'\n'`.
180207
})
181208
})
182209

@@ -226,6 +253,43 @@ describe('reduceCommandCreators', () => {
226253
],
227254
})
228255
})
256+
257+
it('Python commands are joined together', () => {
258+
const initialState: any = {}
259+
const result: any = reduceCommandCreators(
260+
[
261+
curryCommandCreator(pythonHelloWorldCreator, {}),
262+
curryCommandCreator(pythonGoodbyeWorldCreator, {}),
263+
],
264+
invariantContext,
265+
initialState
266+
)
267+
268+
expect(result).toEqual({
269+
commands: [],
270+
warnings: [],
271+
python: 'print("Hello world")\nprint("Goodbye world")',
272+
})
273+
})
274+
275+
it('Python commands mixed with non-Python commands', () => {
276+
const initialState: any = {}
277+
const result: any = reduceCommandCreators(
278+
[
279+
curryCommandCreator(addCreator, { value: 1 }),
280+
curryCommandCreator(pythonHelloWorldCreator, {}),
281+
],
282+
invariantContext,
283+
initialState
284+
)
285+
286+
expect(result).toEqual({
287+
commands: [{ command: 'add', params: { value: 1 } }],
288+
warnings: [],
289+
python: 'print("Hello world")',
290+
// should only get 1 line of Python with no stray newlines or `undefined`s.
291+
})
292+
})
229293
})
230294

231295
describe('commandCreatorsTimeline', () => {
@@ -236,6 +300,7 @@ describe('commandCreatorsTimeline', () => {
236300
curryCommandCreator(addCreatorWithWarning, { value: 4 }),
237301
curryCommandCreator(divideCreator, { value: 0 }),
238302
curryCommandCreator(multiplyCreator, { value: 3 }),
303+
curryCommandCreator(pythonHelloWorldCreator, {}),
239304
],
240305
invariantContext,
241306
initialState
@@ -263,6 +328,7 @@ describe('commandCreatorsTimeline', () => {
263328
],
264329
},
265330
// no more steps in the timeline, stopped by error
331+
// python output is suppressed too
266332
],
267333
})
268334
})
@@ -275,6 +341,7 @@ describe('commandCreatorsTimeline', () => {
275341
curryCommandCreator(addCreatorWithWarning, { value: 3 }),
276342
curryCommandCreator(multiplyCreator, { value: 2 }),
277343
curryCommandCreator(addCreatorWithWarning, { value: 1 }),
344+
curryCommandCreator(pythonHelloWorldCreator, {}),
278345
],
279346
invariantContext,
280347
initialState
@@ -309,6 +376,13 @@ describe('commandCreatorsTimeline', () => {
309376
},
310377
],
311378
},
379+
// Python hello world
380+
{
381+
robotState: { count: 17 },
382+
commands: [],
383+
warnings: [],
384+
python: 'print("Hello world")',
385+
},
312386
])
313387
})
314388
})

step-generation/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ export interface CommandsAndRobotState {
619619
commands: CreateCommand[]
620620
robotState: RobotState
621621
warnings?: CommandCreatorWarning[]
622+
python?: string
622623
}
623624

624625
export interface CommandCreatorErrorResponse {
@@ -629,6 +630,7 @@ export interface CommandCreatorErrorResponse {
629630
export interface CommandsAndWarnings {
630631
commands: CreateCommand[]
631632
warnings?: CommandCreatorWarning[]
633+
python?: string
632634
}
633635
export type CommandCreatorResult =
634636
| CommandsAndWarnings

step-generation/src/utils/commandCreatorsTimeline.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const commandCreatorsTimeline = (
5353
commands: commandCreatorResult.commands,
5454
robotState: nextRobotStateAndWarnings.robotState,
5555
warnings: commandCreatorResult.warnings,
56+
python: commandCreatorResult.python,
5657
}
5758
return {
5859
timeline: [...acc.timeline, nextResult],

step-generation/src/utils/reduceCommandCreators.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ interface CCReducerAcc {
1313
commands: CreateCommand[]
1414
errors: CommandCreatorError[]
1515
warnings: CommandCreatorWarning[]
16+
python?: string
1617
}
1718
export const reduceCommandCreators = (
1819
commandCreators: CurriedCommandCreator[],
@@ -36,6 +37,10 @@ export const reduceCommandCreators = (
3637
}
3738
}
3839
const allCommands = [...prev.commands, ...next.commands]
40+
const allPython = [
41+
...(prev.python ? [prev.python] : []),
42+
...(next.python ? [next.python] : []),
43+
].join('\n')
3944
const updates = getNextRobotStateAndWarnings(
4045
next.commands,
4146
invariantContext,
@@ -50,6 +55,7 @@ export const reduceCommandCreators = (
5055
...(next.warnings || []),
5156
...updates.warnings,
5257
],
58+
...(allPython && { python: allPython }),
5359
}
5460
},
5561
{
@@ -69,5 +75,6 @@ export const reduceCommandCreators = (
6975
return {
7076
commands: result.commands,
7177
warnings: result.warnings,
78+
...(result.python && { python: result.python }),
7279
}
7380
}

0 commit comments

Comments
 (0)