-
Notifications
You must be signed in to change notification settings - Fork 180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(protocol-designer): load module in python file #17483
Changes from 7 commits
3b3f39c
0184ec0
3bb3a87
a08634a
4082495
a7ba157
e84bed5
9e063ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,19 @@ | ||
import { describe, it, expect } from 'vitest' | ||
import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' | ||
import { pythonMetadata, pythonRequirements } from '../selectors/pythonFile' | ||
import { | ||
FLEX_ROBOT_TYPE, | ||
HEATERSHAKER_MODULE_TYPE, | ||
HEATERSHAKER_MODULE_V1, | ||
MAGNETIC_BLOCK_TYPE, | ||
MAGNETIC_BLOCK_V1, | ||
OT2_ROBOT_TYPE, | ||
} from '@opentrons/shared-data' | ||
import { | ||
getLoadModules, | ||
pythonMetadata, | ||
pythonRequirements, | ||
} from '../selectors/pythonFile' | ||
import type { TimelineFrame } from '@opentrons/step-generation' | ||
import type { ModuleEntities } from '../../step-forms' | ||
|
||
describe('pythonMetadata', () => { | ||
it('should generate metadata section', () => { | ||
|
@@ -50,3 +63,43 @@ requirements = { | |
) | ||
}) | ||
}) | ||
|
||
describe('getLoadModules', () => { | ||
it('should generate loadModules', () => { | ||
const moduleId = '1' | ||
const moduleId2 = '2' | ||
const moduleId3 = '3' | ||
const mockModuleEntities: ModuleEntities = { | ||
[moduleId]: { | ||
id: moduleId, | ||
model: MAGNETIC_BLOCK_V1, | ||
type: MAGNETIC_BLOCK_TYPE, | ||
pythonName: 'magnetic_block_1', | ||
}, | ||
[moduleId2]: { | ||
id: moduleId2, | ||
model: HEATERSHAKER_MODULE_V1, | ||
type: HEATERSHAKER_MODULE_TYPE, | ||
pythonName: 'heater_shaker_1', | ||
}, | ||
[moduleId3]: { | ||
id: moduleId3, | ||
model: MAGNETIC_BLOCK_V1, | ||
type: MAGNETIC_BLOCK_TYPE, | ||
pythonName: 'magnetic_block_2', | ||
}, | ||
} | ||
const modules: TimelineFrame['modules'] = { | ||
[moduleId]: { slot: 'B1', moduleState: {} as any }, | ||
[moduleId2]: { slot: 'A1', moduleState: {} as any }, | ||
[moduleId3]: { slot: 'A2', moduleState: {} as any }, | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Could you get rid of the blank line at here before the code in the function? |
||
expect(getLoadModules(mockModuleEntities, modules)).toBe( | ||
`# Load Modules: | ||
magnetic_block_1 = protocol.load_module("magneticBlockV1", "B1") | ||
heater_shaker_1 = protocol.load_module("heaterShakerModuleV1", "A1") | ||
magnetic_block_2 = protocol.load_module("magneticBlockV1", "A2")` | ||
) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,17 @@ | |
import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' | ||
import { | ||
formatPyDict, | ||
formatPyStr, | ||
indentPyLines, | ||
PROTOCOL_CONTEXT_NAME, | ||
} from '@opentrons/step-generation' | ||
import type { FileMetadataFields } from '../types' | ||
import type { | ||
InvariantContext, | ||
ModuleEntities, | ||
TimelineFrame, | ||
} from '@opentrons/step-generation' | ||
import type { RobotType } from '@opentrons/shared-data' | ||
import type { FileMetadataFields } from '../types' | ||
|
||
const PAPI_VERSION = '2.23' // latest version from api/src/opentrons/protocols/api_support/definitions.py | ||
|
||
|
@@ -51,9 +57,37 @@ export function pythonRequirements(robotType: RobotType): string { | |
return `requirements = ${formatPyDict(requirements)}` | ||
} | ||
|
||
export function pythonDefRun(): string { | ||
export function getLoadModules( | ||
moduleEntities: ModuleEntities, | ||
moduleRobotState: TimelineFrame['modules'] | ||
): string { | ||
const hasModules = Object.keys(moduleEntities).length > 0 | ||
const pythonModules = hasModules | ||
? Object.values(moduleEntities) | ||
.map(module => { | ||
// pythonIdentifier from api/src/opentrons/protocol_api/validation.py#L373 | ||
const pythonIdentifier = module.model | ||
return `${ | ||
module.pythonName | ||
} = ${PROTOCOL_CONTEXT_NAME}.load_module(${formatPyStr( | ||
pythonIdentifier | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think just using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yup! fair. |
||
)}, ${formatPyStr(moduleRobotState[module.id].slot)})` | ||
}) | ||
.join('\n') | ||
: '' | ||
return hasModules ? `# Load Modules:\n${pythonModules}` : '' | ||
} | ||
|
||
export function pythonDefRun( | ||
invariantContext: InvariantContext, | ||
robotState: TimelineFrame | ||
): string { | ||
const { moduleEntities } = invariantContext | ||
|
||
const loadModules = getLoadModules(moduleEntities, robotState.modules) | ||
|
||
const sections: string[] = [ | ||
// loadModules(), | ||
loadModules, | ||
// loadLabware(), | ||
// loadInstruments(), | ||
// defineLiquids(), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
turns out the v7Fixture doesn't have a module - should i add one to the fixture so we can test that it works in the unit test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to! But like the comment below says, the point of the tests in this file is just to make sure
createFile()
/createPythonFile()
spit out something that looks like a protocol. We'll have other unit tests in other files to make sure that the generated Python code is actually correct for all possible types of modules/labware/etc.