@opentrons/shared-data 0.0.1-alpha.20 → 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Makefile +1 -1
- package/lib/opentrons-shared-data.js +1 -1
- package/lib/opentrons-shared-data.js.map +1 -1
- package/package.json +1 -1
- package/js/__tests__/__snapshots__/pipettes.test.ts.snap +0 -5969
- package/js/__tests__/deckSchemas.test.ts +0 -87
- package/js/__tests__/errors.test.js +0 -21
- package/js/__tests__/getAreSlotsAdjacent.test.ts +0 -128
- package/js/__tests__/getWellNamePerMultiTip.test.ts +0 -162
- package/js/__tests__/labwareDefQuirks.test.ts +0 -37
- package/js/__tests__/labwareDefSchemaV1.test.ts +0 -82
- package/js/__tests__/labwareDefSchemaV2.test.ts +0 -298
- package/js/__tests__/moduleAccessors.test.ts +0 -50
- package/js/__tests__/moduleSpecsSchema.test.ts +0 -77
- package/js/__tests__/pipetteSchemaV2.test.ts +0 -107
- package/js/__tests__/pipetteSpecSchemas.test.ts +0 -48
- package/js/__tests__/pipettes.test.ts +0 -58
- package/js/__tests__/protocolSchemaV4.test.ts +0 -137
- package/js/__tests__/protocolSchemaV5.test.ts +0 -137
- package/js/__tests__/protocolSchemaV6.test.ts +0 -132
- package/js/__tests__/protocolSchemaV7.test.ts +0 -64
- package/js/__tests__/protocolValidation.test.ts +0 -83
- package/js/__tests__/sortWells.test.ts +0 -40
- package/js/__tests__/splitWellsOnColumn.test.ts +0 -21
- package/js/__tests__/validateErrors.test.js +0 -34
- package/js/constants.ts +0 -338
- package/js/cypressUtils.ts +0 -35
- package/js/errors.ts +0 -33
- package/js/fixtures.ts +0 -161
- package/js/getLabware.ts +0 -154
- package/js/gripper.ts +0 -29
- package/js/helpers/__tests__/getAdapterName.test.ts +0 -31
- package/js/helpers/__tests__/getDeckDefFromLoadedLabware.test.ts +0 -12
- package/js/helpers/__tests__/getVectorDifference.test.ts +0 -25
- package/js/helpers/__tests__/getVectorSum.test.ts +0 -21
- package/js/helpers/__tests__/labwareInference.test.ts +0 -84
- package/js/helpers/__tests__/orderWells.test.ts +0 -87
- package/js/helpers/__tests__/parseProtocolData.test.ts +0 -165
- package/js/helpers/__tests__/volume.test.ts +0 -108
- package/js/helpers/__tests__/wellSets.test.ts +0 -352
- package/js/helpers/get96Channel384WellPlateWells.ts +0 -44
- package/js/helpers/getAddressableAreasInProtocol.ts +0 -59
- package/js/helpers/getLoadedLabwareDefinitionsByUri.ts +0 -30
- package/js/helpers/getModuleVizDims.ts +0 -118
- package/js/helpers/getOccludedSlotCountForModule.ts +0 -13
- package/js/helpers/getVectorDifference.ts +0 -12
- package/js/helpers/getVectorSum.ts +0 -12
- package/js/helpers/getWellNamePerMultiTip.ts +0 -86
- package/js/helpers/getWellTotalVolume.ts +0 -16
- package/js/helpers/index.ts +0 -347
- package/js/helpers/labwareInference.ts +0 -92
- package/js/helpers/orderWells.ts +0 -69
- package/js/helpers/parseProtocolData.ts +0 -141
- package/js/helpers/volume.ts +0 -35
- package/js/helpers/wellIsRect.ts +0 -6
- package/js/helpers/wellSets.ts +0 -155
- package/js/index.ts +0 -14
- package/js/labwareTools/__tests__/__snapshots__/createIrregularLabware.test.ts.snap +0 -3
- package/js/labwareTools/__tests__/__snapshots__/createLabware.test.ts.snap +0 -3
- package/js/labwareTools/__tests__/createDefaultDisplayName.test.ts +0 -111
- package/js/labwareTools/__tests__/createIrregularLabware.test.ts +0 -226
- package/js/labwareTools/__tests__/createLabware.test.ts +0 -147
- package/js/labwareTools/index.ts +0 -452
- package/js/modules.ts +0 -97
- package/js/pipettes.ts +0 -89
- package/js/protocols.ts +0 -290
- package/js/schema.ts +0 -80
- package/js/scripts/generateDeckLayersFromSVG.js +0 -46
- package/js/titleCase.ts +0 -30
- package/js/types.ts +0 -600
- package/python/.coveragerc +0 -4
- package/python/.flake8 +0 -32
- package/python/Config.in +0 -10
- package/python/Makefile +0 -134
- package/python/Pipfile +0 -28
- package/python/Pipfile.lock +0 -645
- package/python/buildroot.mk +0 -30
- package/python/mypy.ini +0 -41
- package/python/opentrons_shared_data/__init__.py +0 -17
- package/python/opentrons_shared_data/_version.py +0 -20
- package/python/opentrons_shared_data/command/__init__.py +0 -52
- package/python/opentrons_shared_data/deck/__init__.py +0 -96
- package/python/opentrons_shared_data/deck/dev_types.py +0 -180
- package/python/opentrons_shared_data/errors/__init__.py +0 -30
- package/python/opentrons_shared_data/errors/categories.py +0 -60
- package/python/opentrons_shared_data/errors/codes.py +0 -108
- package/python/opentrons_shared_data/errors/exceptions.py +0 -915
- package/python/opentrons_shared_data/gripper/__init__.py +0 -63
- package/python/opentrons_shared_data/gripper/constants.py +0 -6
- package/python/opentrons_shared_data/gripper/gripper_definition.py +0 -101
- package/python/opentrons_shared_data/labware/__init__.py +0 -22
- package/python/opentrons_shared_data/labware/constants.py +0 -7
- package/python/opentrons_shared_data/labware/dev_types.py +0 -140
- package/python/opentrons_shared_data/labware/labware_definition.py +0 -328
- package/python/opentrons_shared_data/load.py +0 -57
- package/python/opentrons_shared_data/module/__init__.py +0 -74
- package/python/opentrons_shared_data/module/dev_types.py +0 -141
- package/python/opentrons_shared_data/pipette/__init__.py +0 -107
- package/python/opentrons_shared_data/pipette/dev_types.py +0 -177
- package/python/opentrons_shared_data/pipette/file_operation_helpers.py +0 -37
- package/python/opentrons_shared_data/pipette/load_data.py +0 -261
- package/python/opentrons_shared_data/pipette/model_constants.py +0 -123
- package/python/opentrons_shared_data/pipette/mutable_configurations.py +0 -431
- package/python/opentrons_shared_data/pipette/pipette_definition.py +0 -503
- package/python/opentrons_shared_data/pipette/pipette_load_name_conversions.py +0 -240
- package/python/opentrons_shared_data/pipette/scripts/__init__.py +0 -0
- package/python/opentrons_shared_data/pipette/scripts/build_json_script.py +0 -469
- package/python/opentrons_shared_data/pipette/scripts/update_configuration_files.py +0 -450
- package/python/opentrons_shared_data/pipette/types.py +0 -193
- package/python/opentrons_shared_data/protocol/__init__.py +0 -13
- package/python/opentrons_shared_data/protocol/constants.py +0 -98
- package/python/opentrons_shared_data/protocol/dev_types.py +0 -436
- package/python/opentrons_shared_data/protocol/models/__init__.py +0 -48
- package/python/opentrons_shared_data/protocol/models/protocol_schema_v6.py +0 -145
- package/python/opentrons_shared_data/protocol/models/protocol_schema_v7.py +0 -95
- package/python/opentrons_shared_data/protocol/models/protocol_schema_v8.py +0 -110
- package/python/opentrons_shared_data/protocol/models/shared_models.py +0 -111
- package/python/opentrons_shared_data/py.typed +0 -0
- package/python/opentrons_shared_data/robot/__init__.py +0 -33
- package/python/opentrons_shared_data/robot/dev_types.py +0 -37
- package/python/pytest.ini +0 -2
- package/python/setup.cfg +0 -5
- package/python/setup.py +0 -179
- package/python/tests/__init__.py +0 -1
- package/python/tests/conftest.py +0 -0
- package/python/tests/deck/__init__.py +0 -0
- package/python/tests/deck/test_list_names.py +0 -12
- package/python/tests/deck/test_position.py +0 -113
- package/python/tests/deck/test_typechecks.py +0 -28
- package/python/tests/errors/__init__.py +0 -1
- package/python/tests/errors/test_error_completeness.py +0 -19
- package/python/tests/errors/test_exceptions.py +0 -74
- package/python/tests/gripper/__init__.py +0 -0
- package/python/tests/gripper/test_definition.py +0 -30
- package/python/tests/gripper/test_load.py +0 -16
- package/python/tests/labware/__init__.py +0 -13
- package/python/tests/labware/test_typechecks.py +0 -21
- package/python/tests/module/__init__.py +0 -20
- package/python/tests/module/test_load.py +0 -49
- package/python/tests/module/test_typechecks.py +0 -34
- package/python/tests/pipette/__init__.py +0 -0
- package/python/tests/pipette/test_load_data.py +0 -103
- package/python/tests/pipette/test_mutable_configurations.py +0 -266
- package/python/tests/pipette/test_pipette_definition.py +0 -183
- package/python/tests/pipette/test_pipette_load_name_conversions.py +0 -222
- package/python/tests/pipette/test_typechecks.py +0 -50
- package/python/tests/pipette/test_validate_schema.py +0 -37
- package/python/tests/protocol/__init__.py +0 -15
- package/python/tests/protocol/test_protocol_schema_v6.py +0 -107
- package/python/tests/protocol/test_protocol_schema_v7.py +0 -34
- package/python/tests/protocol/test_protocol_schema_v8.py +0 -20
- package/python/tests/protocol/test_typechecks.py +0 -36
- package/python/tests/robot/__init__.py +0 -0
- package/python/tests/robot/test_typechecks.py +0 -20
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import Ajv from 'ajv'
|
|
2
|
-
import labwareV2Schema from '../../labware/schemas/2.json'
|
|
3
|
-
import protocolSchemaV1 from '../../protocol/schemas/1.json'
|
|
4
|
-
import protocolSchemaV2 from '../../protocol/schemas/2.json'
|
|
5
|
-
import protocolSchemaV3 from '../../protocol/schemas/3.json'
|
|
6
|
-
import protocolSchemaV4 from '../../protocol/schemas/4.json'
|
|
7
|
-
import protocolSchemaV5 from '../../protocol/schemas/5.json'
|
|
8
|
-
|
|
9
|
-
import type { ErrorObject } from 'ajv'
|
|
10
|
-
import type { JsonProtocolFile } from '../../protocol'
|
|
11
|
-
|
|
12
|
-
export type ProtocolParseErrorKey = 'INVALID_FILE_TYPE' | 'INVALID_JSON_FILE'
|
|
13
|
-
|
|
14
|
-
interface ProtocolParseErrorDetails {
|
|
15
|
-
rawError?: string
|
|
16
|
-
schemaErrors?: ErrorObject[] | null
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export type ProtocolParseErrorHandler = (
|
|
20
|
-
errorKey: ProtocolParseErrorKey,
|
|
21
|
-
errorDetails?: ProtocolParseErrorDetails
|
|
22
|
-
) => unknown
|
|
23
|
-
|
|
24
|
-
type ProtocolSchema =
|
|
25
|
-
| typeof protocolSchemaV1
|
|
26
|
-
| typeof protocolSchemaV2
|
|
27
|
-
| typeof protocolSchemaV3
|
|
28
|
-
| typeof protocolSchemaV4
|
|
29
|
-
| typeof protocolSchemaV5
|
|
30
|
-
|
|
31
|
-
const SCHEMA_BY_VERSION: { [version: string]: ProtocolSchema } = {
|
|
32
|
-
'1': protocolSchemaV1,
|
|
33
|
-
'2': protocolSchemaV2,
|
|
34
|
-
'3': protocolSchemaV3,
|
|
35
|
-
'4': protocolSchemaV4,
|
|
36
|
-
'5': protocolSchemaV5,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface PythonProtocolMetadata {
|
|
40
|
-
source?: string
|
|
41
|
-
[key: string]: unknown
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// data may be a full JSON protocol or just a metadata dict from Python
|
|
45
|
-
export type ProtocolData =
|
|
46
|
-
| JsonProtocolFile
|
|
47
|
-
| { metadata: PythonProtocolMetadata }
|
|
48
|
-
|
|
49
|
-
export function parseProtocolData(
|
|
50
|
-
file: File,
|
|
51
|
-
contents: string,
|
|
52
|
-
handleError?: ProtocolParseErrorHandler,
|
|
53
|
-
metadata?: PythonProtocolMetadata | null // optional Python protocol metadata
|
|
54
|
-
): ProtocolData | null {
|
|
55
|
-
if (fileExtensionIsJson(file.name)) {
|
|
56
|
-
return validateJsonProtocolFileContents(contents, handleError)
|
|
57
|
-
} else if (fileExtensionIsPython(file.name)) {
|
|
58
|
-
// grab Python protocol metadata, if any
|
|
59
|
-
return metadata != null ? { metadata } : null
|
|
60
|
-
} else if (fileExtensionIsZip(file.name)) {
|
|
61
|
-
return null
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
handleError && handleError('INVALID_FILE_TYPE')
|
|
65
|
-
return null
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function fileExtensionIsPython(filename: string): boolean {
|
|
69
|
-
return Boolean(/\.py$/i.test(filename))
|
|
70
|
-
}
|
|
71
|
-
export function fileExtensionIsJson(filename: string): boolean {
|
|
72
|
-
return Boolean(/\.json$/i.test(filename))
|
|
73
|
-
}
|
|
74
|
-
export function fileExtensionIsZip(filename: string): boolean {
|
|
75
|
-
return Boolean(/\.zip$/i.test(filename))
|
|
76
|
-
}
|
|
77
|
-
export function fileIsBinary(file: File): boolean {
|
|
78
|
-
// bundles are always binary files, and currently nothing else is binary
|
|
79
|
-
return fileExtensionIsZip(file.name)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function validateJsonProtocolFileContents(
|
|
83
|
-
fileContents: string,
|
|
84
|
-
handleError?: ProtocolParseErrorHandler
|
|
85
|
-
): JsonProtocolFile | null {
|
|
86
|
-
try {
|
|
87
|
-
if (typeof fileContents !== 'string') {
|
|
88
|
-
handleError && handleError('INVALID_FILE_TYPE')
|
|
89
|
-
return null
|
|
90
|
-
} else {
|
|
91
|
-
const ajv = new Ajv({ allErrors: true, jsonPointers: true })
|
|
92
|
-
// protocol schema contains reference to v2 labware schema, so give AJV access to it
|
|
93
|
-
ajv.addSchema(labwareV2Schema)
|
|
94
|
-
|
|
95
|
-
const parsedProtocol = JSON.parse(fileContents) as any
|
|
96
|
-
let validateAgainstSchema
|
|
97
|
-
if ('protocol-schema' in parsedProtocol) {
|
|
98
|
-
// 'protocol-schema' key only present in V1
|
|
99
|
-
validateAgainstSchema = ajv.compile(protocolSchemaV1)
|
|
100
|
-
} else {
|
|
101
|
-
const { schemaVersion } = parsedProtocol
|
|
102
|
-
validateAgainstSchema = ajv.compile(
|
|
103
|
-
SCHEMA_BY_VERSION[String(schemaVersion)]
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (!validateAgainstSchema(parsedProtocol)) {
|
|
108
|
-
handleError &&
|
|
109
|
-
handleError('INVALID_JSON_FILE', {
|
|
110
|
-
schemaErrors: validateAgainstSchema.errors,
|
|
111
|
-
})
|
|
112
|
-
return null
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return parsedProtocol
|
|
116
|
-
}
|
|
117
|
-
} catch (error) {
|
|
118
|
-
handleError && handleError('INVALID_JSON_FILE', { rawError: error })
|
|
119
|
-
return null
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export function getProtocolDesignerApplicationName(
|
|
124
|
-
protocol: JsonProtocolFile
|
|
125
|
-
): string | null {
|
|
126
|
-
if (
|
|
127
|
-
'designerApplication' in protocol &&
|
|
128
|
-
protocol.designerApplication != null
|
|
129
|
-
) {
|
|
130
|
-
return 'name' in protocol.designerApplication &&
|
|
131
|
-
protocol.designerApplication.name != null
|
|
132
|
-
? protocol.designerApplication.name
|
|
133
|
-
: null
|
|
134
|
-
} else if (
|
|
135
|
-
'designer-application' in protocol &&
|
|
136
|
-
protocol['designer-application']['application-name'] != null
|
|
137
|
-
) {
|
|
138
|
-
return protocol['designer-application']['application-name']
|
|
139
|
-
}
|
|
140
|
-
return null
|
|
141
|
-
}
|
package/js/helpers/volume.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// utilities for working with volumes in µL
|
|
2
|
-
import round from 'lodash/round'
|
|
3
|
-
|
|
4
|
-
import type { LabwareVolumeUnits } from '../types'
|
|
5
|
-
|
|
6
|
-
const SCALE_BY_UNITS = {
|
|
7
|
-
µL: 1,
|
|
8
|
-
mL: 1000,
|
|
9
|
-
L: 1000000,
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function getDisplayVolume(
|
|
13
|
-
volumeInMicroliters: number,
|
|
14
|
-
displayUnits: LabwareVolumeUnits = 'µL',
|
|
15
|
-
digits?: number
|
|
16
|
-
): string {
|
|
17
|
-
const volume = volumeInMicroliters / SCALE_BY_UNITS[displayUnits]
|
|
18
|
-
|
|
19
|
-
return `${typeof digits === 'number' ? round(volume, digits) : volume}`
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function getAsciiVolumeUnits(displayUnits: LabwareVolumeUnits): string {
|
|
23
|
-
if (displayUnits === 'µL') return 'uL'
|
|
24
|
-
|
|
25
|
-
return displayUnits
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function ensureVolumeUnits(
|
|
29
|
-
maybeUnits: string | null | undefined
|
|
30
|
-
): LabwareVolumeUnits {
|
|
31
|
-
if (maybeUnits === 'mL' || maybeUnits === 'ml') return 'mL'
|
|
32
|
-
if (maybeUnits === 'L' || maybeUnits === 'l') return 'L'
|
|
33
|
-
|
|
34
|
-
return 'µL'
|
|
35
|
-
}
|
package/js/helpers/wellIsRect.ts
DELETED
package/js/helpers/wellSets.ts
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
// A "well set" is an array of wells corresponding to each tip of an 8 channel pipette.
|
|
2
|
-
// Eg ['A1', 'C1', 'E1', 'G1', 'I1', 'K1', 'M1', 'O1'] is a well set in a 384 plate.
|
|
3
|
-
//
|
|
4
|
-
// A trough-like well that encompasses all 8 tips at once has a well set
|
|
5
|
-
// ['A1', 'A1', 'A1', 'A1', 'A1', 'A1', 'A1', 'A1']
|
|
6
|
-
//
|
|
7
|
-
// Well sets are determined by geometry.
|
|
8
|
-
//
|
|
9
|
-
// Labware with multiple positions for an 8-channel pipette have multiple well sets.
|
|
10
|
-
// For example, a 96 plate has 12 well sets, one for each column.
|
|
11
|
-
// A 384 plate has 48 well sets, 2 for each column b/c it has staggered columns.
|
|
12
|
-
//
|
|
13
|
-
// If a labware has no possible well sets, then it is not compatible with multi-channel pipettes.
|
|
14
|
-
import uniq from 'lodash/uniq'
|
|
15
|
-
|
|
16
|
-
import { getWellNamePerMultiTip } from './getWellNamePerMultiTip'
|
|
17
|
-
import { get96Channel384WellPlateWells, getLabwareDefURI, orderWells } from '.'
|
|
18
|
-
import type { LabwareDefinition2, PipetteNameSpecs } from '../types'
|
|
19
|
-
|
|
20
|
-
type WellSetByPrimaryWell = string[][]
|
|
21
|
-
|
|
22
|
-
// Compute all well sets for a labware def (non-memoized)
|
|
23
|
-
function _getAllWellSetsForLabware(
|
|
24
|
-
labwareDef: LabwareDefinition2
|
|
25
|
-
): WellSetByPrimaryWell {
|
|
26
|
-
const allWells: string[] = Object.keys(labwareDef.wells)
|
|
27
|
-
|
|
28
|
-
return allWells.reduce(
|
|
29
|
-
(acc: WellSetByPrimaryWell, well: string): WellSetByPrimaryWell => {
|
|
30
|
-
const wellSet = getWellNamePerMultiTip(labwareDef, well, 8)
|
|
31
|
-
if (wellSet === null) {
|
|
32
|
-
return acc
|
|
33
|
-
} else {
|
|
34
|
-
return [...acc, wellSet]
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
[]
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// creates memoized getAllWellSetsForLabware + getWellSetForMultichannel fns.
|
|
42
|
-
export interface WellSetHelpers {
|
|
43
|
-
getAllWellSetsForLabware: (
|
|
44
|
-
labwareDef: LabwareDefinition2
|
|
45
|
-
) => WellSetByPrimaryWell
|
|
46
|
-
|
|
47
|
-
getWellSetForMultichannel: (
|
|
48
|
-
labwareDef: LabwareDefinition2,
|
|
49
|
-
well: string,
|
|
50
|
-
channels: 8 | 96
|
|
51
|
-
) => string[] | null | undefined
|
|
52
|
-
|
|
53
|
-
canPipetteUseLabware: (
|
|
54
|
-
pipetteSpec: PipetteNameSpecs,
|
|
55
|
-
labwareDef?: LabwareDefinition2,
|
|
56
|
-
trashName?: string
|
|
57
|
-
) => boolean
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export const makeWellSetHelpers = (): WellSetHelpers => {
|
|
61
|
-
const cache: Partial<{
|
|
62
|
-
[labwareDefURI: string]: {
|
|
63
|
-
labwareDef: LabwareDefinition2
|
|
64
|
-
wellSetByPrimaryWell: WellSetByPrimaryWell
|
|
65
|
-
} | null
|
|
66
|
-
}> = {}
|
|
67
|
-
|
|
68
|
-
const getAllWellSetsForLabware = (
|
|
69
|
-
labwareDef: LabwareDefinition2
|
|
70
|
-
): WellSetByPrimaryWell => {
|
|
71
|
-
const labwareDefURI = getLabwareDefURI(labwareDef)
|
|
72
|
-
const c = cache[labwareDefURI]
|
|
73
|
-
|
|
74
|
-
// use cached version only if labwareDef is shallowly equal, in case
|
|
75
|
-
// custom labware defs are changed without giving them a new URI
|
|
76
|
-
if (c && c.labwareDef === labwareDef) {
|
|
77
|
-
return c.wellSetByPrimaryWell
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const wellSetByPrimaryWell = _getAllWellSetsForLabware(labwareDef)
|
|
81
|
-
|
|
82
|
-
cache[labwareDefURI] = {
|
|
83
|
-
labwareDef,
|
|
84
|
-
wellSetByPrimaryWell,
|
|
85
|
-
}
|
|
86
|
-
return wellSetByPrimaryWell
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const getWellSetForMultichannel = (
|
|
90
|
-
labwareDef: LabwareDefinition2,
|
|
91
|
-
well: string,
|
|
92
|
-
channels: 8 | 96
|
|
93
|
-
): string[] | null | undefined => {
|
|
94
|
-
/** Given a well for a labware, returns the well set it belongs to (or null)
|
|
95
|
-
* for 8-channel access.
|
|
96
|
-
* Ie: C2 for 96-flat => ['A2', 'B2', 'C2', ... 'H2']
|
|
97
|
-
* Or A1 for trough => ['A1', 'A1', 'A1', ...]
|
|
98
|
-
**/
|
|
99
|
-
const allWellSetsFor8Channel = getAllWellSetsForLabware(labwareDef)
|
|
100
|
-
/** getting all wells from the plate and turning into 1D array for 96-channel
|
|
101
|
-
*/
|
|
102
|
-
const orderedWellsFor96Channel = orderWells(
|
|
103
|
-
labwareDef.ordering,
|
|
104
|
-
't2b',
|
|
105
|
-
'l2r'
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
let ninetySixChannelWells = orderedWellsFor96Channel
|
|
109
|
-
/** special casing 384 well plates to be every other well
|
|
110
|
-
* both on the x and y ases.
|
|
111
|
-
*/
|
|
112
|
-
if (orderedWellsFor96Channel.length === 384) {
|
|
113
|
-
ninetySixChannelWells = get96Channel384WellPlateWells(
|
|
114
|
-
orderedWellsFor96Channel,
|
|
115
|
-
well
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
return channels === 8
|
|
119
|
-
? allWellSetsFor8Channel.find((wellSet: string[]) =>
|
|
120
|
-
wellSet.includes(well)
|
|
121
|
-
)
|
|
122
|
-
: ninetySixChannelWells
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const canPipetteUseLabware = (
|
|
126
|
-
pipetteSpec: PipetteNameSpecs,
|
|
127
|
-
labwareDef?: LabwareDefinition2,
|
|
128
|
-
trashName?: string
|
|
129
|
-
): boolean => {
|
|
130
|
-
if (pipetteSpec.channels === 1 || trashName != null) {
|
|
131
|
-
// assume all labware can be used by single-channel
|
|
132
|
-
return true
|
|
133
|
-
}
|
|
134
|
-
if (labwareDef != null) {
|
|
135
|
-
const allWellSets = getAllWellSetsForLabware(labwareDef)
|
|
136
|
-
return allWellSets.some(wellSet => {
|
|
137
|
-
const uniqueWells = uniq(wellSet)
|
|
138
|
-
// if all wells are non-null, and there are either 1 (reservoir-like)
|
|
139
|
-
// or 8 (well plate-like) unique wells in the set,
|
|
140
|
-
// then assume both 8 and 96 channel pipettes will work
|
|
141
|
-
return (
|
|
142
|
-
uniqueWells.every(well => well != null) &&
|
|
143
|
-
[1, 8].includes(uniqueWells.length)
|
|
144
|
-
)
|
|
145
|
-
})
|
|
146
|
-
} else {
|
|
147
|
-
return false
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return {
|
|
151
|
-
getAllWellSetsForLabware,
|
|
152
|
-
getWellSetForMultichannel,
|
|
153
|
-
canPipetteUseLabware,
|
|
154
|
-
}
|
|
155
|
-
}
|
package/js/index.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export * from './constants'
|
|
2
|
-
export * from './getLabware'
|
|
3
|
-
export * from './helpers'
|
|
4
|
-
export * from './pipettes'
|
|
5
|
-
export * from './types'
|
|
6
|
-
export * from './labwareTools'
|
|
7
|
-
export * from './modules'
|
|
8
|
-
export * from './fixtures'
|
|
9
|
-
export * from './gripper'
|
|
10
|
-
export * from '../protocol'
|
|
11
|
-
export * from '../deck'
|
|
12
|
-
export * from './titleCase'
|
|
13
|
-
export * from './errors'
|
|
14
|
-
export * from './fixtures'
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { createDefaultDisplayName } from '..'
|
|
2
|
-
|
|
3
|
-
import type { RegularNameProps } from '..'
|
|
4
|
-
|
|
5
|
-
interface TestCase {
|
|
6
|
-
testName: string
|
|
7
|
-
args: RegularNameProps
|
|
8
|
-
expected: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
describe('createDefaultDisplayName', () => {
|
|
12
|
-
const testCases: TestCase[] = [
|
|
13
|
-
{
|
|
14
|
-
testName: 'handle the minimal case',
|
|
15
|
-
args: {
|
|
16
|
-
displayCategory: 'wellPlate',
|
|
17
|
-
displayVolumeUnits: 'µL',
|
|
18
|
-
gridRows: 2,
|
|
19
|
-
gridColumns: 3,
|
|
20
|
-
totalLiquidVolume: 123,
|
|
21
|
-
},
|
|
22
|
-
expected: 'Generic 6 Well Plate 123 µL',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
testName: 'handle a decimal in volume',
|
|
26
|
-
args: {
|
|
27
|
-
displayCategory: 'wellPlate',
|
|
28
|
-
displayVolumeUnits: 'µL',
|
|
29
|
-
gridRows: 2,
|
|
30
|
-
gridColumns: 3,
|
|
31
|
-
totalLiquidVolume: 12.3,
|
|
32
|
-
},
|
|
33
|
-
expected: 'Generic 6 Well Plate 12.3 µL',
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
testName: 'calculate wells = rows x cols',
|
|
37
|
-
args: {
|
|
38
|
-
displayCategory: 'wellPlate',
|
|
39
|
-
displayVolumeUnits: 'µL',
|
|
40
|
-
gridRows: 8,
|
|
41
|
-
gridColumns: 10,
|
|
42
|
-
totalLiquidVolume: 123,
|
|
43
|
-
},
|
|
44
|
-
expected: 'Generic 80 Well Plate 123 µL',
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
testName: 'handle tube rack (example of a different displayCategory)',
|
|
48
|
-
args: {
|
|
49
|
-
displayCategory: 'tubeRack',
|
|
50
|
-
displayVolumeUnits: 'µL',
|
|
51
|
-
gridRows: 2,
|
|
52
|
-
gridColumns: 3,
|
|
53
|
-
totalLiquidVolume: 123,
|
|
54
|
-
},
|
|
55
|
-
expected: 'Generic 6 Tube Rack 123 µL',
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
testName: 'append loadNamePostfix',
|
|
59
|
-
args: {
|
|
60
|
-
displayCategory: 'wellPlate',
|
|
61
|
-
displayVolumeUnits: 'µL',
|
|
62
|
-
gridRows: 2,
|
|
63
|
-
gridColumns: 3,
|
|
64
|
-
totalLiquidVolume: 123,
|
|
65
|
-
loadNamePostfix: ['spam ', ' blah', 'PCR'],
|
|
66
|
-
},
|
|
67
|
-
expected: 'Generic 6 Well Plate 123 µL Spam Blah PCR',
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
testName: 'support brand name when specified (ignore extra whitespace)',
|
|
71
|
-
args: {
|
|
72
|
-
displayCategory: 'wellPlate',
|
|
73
|
-
displayVolumeUnits: 'µL',
|
|
74
|
-
gridRows: 2,
|
|
75
|
-
gridColumns: 3,
|
|
76
|
-
totalLiquidVolume: 123,
|
|
77
|
-
brandName: ' cool brand ',
|
|
78
|
-
},
|
|
79
|
-
expected: 'Cool Brand 6 Well Plate 123 µL',
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
testName: 'support brand name when specified (capitalization)',
|
|
83
|
-
args: {
|
|
84
|
-
displayCategory: 'wellPlate',
|
|
85
|
-
displayVolumeUnits: 'µL',
|
|
86
|
-
gridRows: 2,
|
|
87
|
-
gridColumns: 3,
|
|
88
|
-
totalLiquidVolume: 123,
|
|
89
|
-
brandName: ' BIO tech',
|
|
90
|
-
},
|
|
91
|
-
expected: 'BIO Tech 6 Well Plate 123 µL',
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
testName: 'support mL when specified (volume number always in µL!)',
|
|
95
|
-
args: {
|
|
96
|
-
displayCategory: 'wellPlate',
|
|
97
|
-
displayVolumeUnits: 'mL',
|
|
98
|
-
gridRows: 2,
|
|
99
|
-
gridColumns: 3,
|
|
100
|
-
totalLiquidVolume: 123,
|
|
101
|
-
},
|
|
102
|
-
expected: 'Generic 6 Well Plate 0.123 mL',
|
|
103
|
-
},
|
|
104
|
-
]
|
|
105
|
-
|
|
106
|
-
testCases.forEach(({ testName, args, expected }) => {
|
|
107
|
-
it(`should ${testName}`, () => {
|
|
108
|
-
expect(createDefaultDisplayName(args)).toEqual(expected)
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
})
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import omit from 'lodash/omit'
|
|
2
|
-
import range from 'lodash/range'
|
|
3
|
-
|
|
4
|
-
import { splitWellsOnColumn, sortWells } from '../../helpers/index'
|
|
5
|
-
import fixture_irregular_example_1 from '../../../labware/fixtures/2/fixture_irregular_example_1.json'
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
createIrregularLabware,
|
|
9
|
-
_irregularWellName,
|
|
10
|
-
_generateIrregularLoadName,
|
|
11
|
-
_calculateWellCoord,
|
|
12
|
-
} from '..'
|
|
13
|
-
|
|
14
|
-
import type { LabwareDefinition2, LabwareWellProperties } from '../../types'
|
|
15
|
-
import type { IrregularLabwareProps } from '..'
|
|
16
|
-
|
|
17
|
-
// NOTE: loadName needs to be replaced here b/c fixture has a non-default loadName
|
|
18
|
-
const exampleLabware1 = {
|
|
19
|
-
...fixture_irregular_example_1,
|
|
20
|
-
parameters: {
|
|
21
|
-
...fixture_irregular_example_1.parameters,
|
|
22
|
-
loadName: 'generic_55_tuberack_50x3ml_5x10ml',
|
|
23
|
-
},
|
|
24
|
-
} as LabwareDefinition2
|
|
25
|
-
|
|
26
|
-
describe('test helper functions', () => {
|
|
27
|
-
it('Well name generated correctly', () => {
|
|
28
|
-
const grid = { row: 2, column: 2 }
|
|
29
|
-
|
|
30
|
-
const gridStart = [
|
|
31
|
-
{ rowStart: 'A', colStart: '1', rowStride: 1, colStride: 2 },
|
|
32
|
-
{ rowStart: 'B', colStart: '1', rowStride: 3, colStride: 1 },
|
|
33
|
-
]
|
|
34
|
-
const expected1 = ['A1', 'B1', 'A3', 'B3']
|
|
35
|
-
const expected2 = ['B1', 'E1', 'B2', 'E2']
|
|
36
|
-
|
|
37
|
-
range(grid.column).forEach(colIdx => {
|
|
38
|
-
range(grid.row).forEach(rowIdx => {
|
|
39
|
-
const idx = colIdx * grid.row + rowIdx
|
|
40
|
-
|
|
41
|
-
const wellName1 = _irregularWellName(rowIdx, colIdx, gridStart[0])
|
|
42
|
-
|
|
43
|
-
expect(expected1[idx]).toEqual(wellName1)
|
|
44
|
-
|
|
45
|
-
const wellName2 = _irregularWellName(rowIdx, colIdx, gridStart[1])
|
|
46
|
-
|
|
47
|
-
expect(expected2[idx]).toEqual(wellName2)
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('XYZ generates correctly for each grid', () => {
|
|
53
|
-
const grid = { row: 1, column: 5 }
|
|
54
|
-
const offset = { x: 1, y: 0.5, z: 55.5 }
|
|
55
|
-
const spacing = [
|
|
56
|
-
{ row: 10, column: 10 },
|
|
57
|
-
{ row: 5, column: 14 },
|
|
58
|
-
]
|
|
59
|
-
const well = [
|
|
60
|
-
omit(exampleLabware1.wells.A1, ['x', 'y', 'z']),
|
|
61
|
-
omit(exampleLabware1.wells.B1, ['x', 'y', 'z']),
|
|
62
|
-
] as LabwareWellProperties[]
|
|
63
|
-
|
|
64
|
-
const expectedX1 = [1, 11, 21, 31, 41]
|
|
65
|
-
const expectedY1 = [0.5]
|
|
66
|
-
const expectedX2 = [1, 15, 29, 43, 57]
|
|
67
|
-
const expectedY2 = [0.5]
|
|
68
|
-
|
|
69
|
-
range(grid.column).forEach(colIdx => {
|
|
70
|
-
range(grid.row).forEach(rowIdx => {
|
|
71
|
-
const well1 = _calculateWellCoord(
|
|
72
|
-
rowIdx,
|
|
73
|
-
colIdx,
|
|
74
|
-
spacing[0],
|
|
75
|
-
offset,
|
|
76
|
-
well[0]
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
expect(well1.x).toBeCloseTo(expectedX1[colIdx], 2)
|
|
80
|
-
expect(well1.y).toBeCloseTo(expectedY1[rowIdx], 2)
|
|
81
|
-
expect(well1.z).toBeCloseTo(offset.z - well[0].depth, 2)
|
|
82
|
-
|
|
83
|
-
const well2 = _calculateWellCoord(
|
|
84
|
-
rowIdx,
|
|
85
|
-
colIdx,
|
|
86
|
-
spacing[1],
|
|
87
|
-
offset,
|
|
88
|
-
well[1]
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
expect(well2.x).toBeCloseTo(expectedX2[colIdx], 2)
|
|
92
|
-
expect(well2.y).toBeCloseTo(expectedY2[rowIdx], 2)
|
|
93
|
-
expect(well2.z).toBeCloseTo(offset.z - well[1].depth, 2)
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
describe('test createIrregularLabware function', () => {
|
|
100
|
-
let labware1: LabwareDefinition2
|
|
101
|
-
let labware1Args: IrregularLabwareProps
|
|
102
|
-
|
|
103
|
-
beforeEach(() => {
|
|
104
|
-
labware1Args = {
|
|
105
|
-
namespace: 'fixture',
|
|
106
|
-
metadata: {
|
|
107
|
-
displayName: 'Fake Irregular Container',
|
|
108
|
-
displayCategory: 'tubeRack',
|
|
109
|
-
displayVolumeUnits: 'mL',
|
|
110
|
-
tags: ['fake', 'opentrons'],
|
|
111
|
-
},
|
|
112
|
-
parameters: {
|
|
113
|
-
format: 'irregular',
|
|
114
|
-
isTiprack: false,
|
|
115
|
-
isMagneticModuleCompatible: false,
|
|
116
|
-
},
|
|
117
|
-
dimensions: {
|
|
118
|
-
xDimension: 127.76,
|
|
119
|
-
yDimension: 85.48,
|
|
120
|
-
zDimension: 64.48,
|
|
121
|
-
},
|
|
122
|
-
well: [
|
|
123
|
-
{
|
|
124
|
-
depth: 10.54,
|
|
125
|
-
shape: 'circular',
|
|
126
|
-
diameter: 10,
|
|
127
|
-
totalLiquidVolume: 3000,
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
depth: 20.54,
|
|
131
|
-
shape: 'circular',
|
|
132
|
-
diameter: 15,
|
|
133
|
-
totalLiquidVolume: 10000,
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
offset: [
|
|
137
|
-
{ x: 10, y: 10, z: 69.48 },
|
|
138
|
-
{ x: 15, y: 15, z: 69.48 },
|
|
139
|
-
],
|
|
140
|
-
grid: [
|
|
141
|
-
{ row: 5, column: 10 },
|
|
142
|
-
{ row: 1, column: 5 },
|
|
143
|
-
],
|
|
144
|
-
spacing: [
|
|
145
|
-
{ row: 5, column: 10 },
|
|
146
|
-
{ row: 5, column: 10 },
|
|
147
|
-
],
|
|
148
|
-
gridStart: [
|
|
149
|
-
{ rowStart: 'A', colStart: '1', rowStride: 2, colStride: 1 },
|
|
150
|
-
{ rowStart: 'B', colStart: '1', rowStride: 1, colStride: 1 },
|
|
151
|
-
],
|
|
152
|
-
}
|
|
153
|
-
labware1 = createIrregularLabware(labware1Args)
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
it('irregular ordering generates as expected', () => {
|
|
157
|
-
const keyList = Object.keys(labware1.wells)
|
|
158
|
-
const generatedOrdering = splitWellsOnColumn(keyList.sort(sortWells))
|
|
159
|
-
expect(labware1.ordering).toEqual(generatedOrdering)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('check labware matches fixture', () => {
|
|
163
|
-
expect(labware1).toEqual(exampleLabware1)
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
it('labware loadName generated correctly for multi-grid labware', () => {
|
|
167
|
-
const loadName = _generateIrregularLoadName({
|
|
168
|
-
grid: [
|
|
169
|
-
{ row: 3, column: 2 },
|
|
170
|
-
{ row: 1, column: 4 },
|
|
171
|
-
],
|
|
172
|
-
well: [
|
|
173
|
-
{
|
|
174
|
-
depth: 20,
|
|
175
|
-
shape: 'circular',
|
|
176
|
-
totalLiquidVolume: 400,
|
|
177
|
-
} as LabwareWellProperties,
|
|
178
|
-
{
|
|
179
|
-
depth: 110,
|
|
180
|
-
shape: 'circular',
|
|
181
|
-
totalLiquidVolume: 2000,
|
|
182
|
-
} as LabwareWellProperties,
|
|
183
|
-
],
|
|
184
|
-
totalWellCount: 10,
|
|
185
|
-
units: 'µL',
|
|
186
|
-
displayCategory: 'wellPlate',
|
|
187
|
-
brand: 'some brand',
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
expect(loadName).toEqual('somebrand_10_wellplate_6x400ul_4x2000ul')
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
it('labware loadName generated correctly for multi-grid labware in other units', () => {
|
|
194
|
-
const loadName = _generateIrregularLoadName({
|
|
195
|
-
grid: [{ row: 3, column: 2 }],
|
|
196
|
-
well: [
|
|
197
|
-
{
|
|
198
|
-
depth: 20,
|
|
199
|
-
shape: 'circular',
|
|
200
|
-
totalLiquidVolume: 4000,
|
|
201
|
-
} as LabwareWellProperties,
|
|
202
|
-
],
|
|
203
|
-
totalWellCount: 6,
|
|
204
|
-
units: 'mL',
|
|
205
|
-
displayCategory: 'wellPlate',
|
|
206
|
-
brand: 'some brand',
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
expect(loadName).toEqual('somebrand_6_wellplate_6x4ml')
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
it('failing to validate against labware schema throws w/o "strict"', () => {
|
|
213
|
-
const args = {
|
|
214
|
-
...labware1Args,
|
|
215
|
-
// negative y offset should fail schema validation by making well `y` negative
|
|
216
|
-
offset: [
|
|
217
|
-
{ x: 10, y: -9999, z: 69.48 },
|
|
218
|
-
{ x: 15, y: -9999, z: 69.48 },
|
|
219
|
-
],
|
|
220
|
-
}
|
|
221
|
-
expect(() => createIrregularLabware(args)).toThrowErrorMatchingSnapshot()
|
|
222
|
-
expect(() =>
|
|
223
|
-
createIrregularLabware({ ...args, strict: false })
|
|
224
|
-
).not.toThrow()
|
|
225
|
-
})
|
|
226
|
-
})
|