@opentrons/shared-data 0.1.7-alpha.1 → 0.2.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.
Files changed (258) hide show
  1. package/.coveragerc +4 -0
  2. package/.flake8 +31 -0
  3. package/Config.in +11 -0
  4. package/LICENSE +202 -0
  5. package/Makefile +13 -14
  6. package/Makefile-python.mk +134 -0
  7. package/buildroot.mk +35 -0
  8. package/command/index.ts +3 -1
  9. package/command/schemas/13.json +147 -315
  10. package/command/schemas/14.json +7254 -0
  11. package/command/types/index.ts +15 -4
  12. package/command/types/module.ts +24 -4
  13. package/command/types/setup.ts +5 -5
  14. package/command/types/support.ts +1 -0
  15. package/deck/definitions/5/ot2_short_trash.json +37 -0
  16. package/deck/definitions/5/ot2_standard.json +37 -0
  17. package/deck/definitions/5/ot3_standard.json +152 -51
  18. package/deck/schemas/5.json +46 -1
  19. package/labware/definitions/2/appliedbiosystemsmicroamp_384_wellplate_40ul/3.json +4737 -0
  20. package/labware/definitions/2/axygen_96_wellplate_500ul/1.json +1036 -0
  21. package/labware/definitions/2/axygen_96_wellplate_500ul/2.json +1159 -0
  22. package/labware/definitions/2/biorad_384_wellplate_50ul/4.json +4748 -0
  23. package/labware/definitions/2/biorad_96_wellplate_200ul_pcr/4.json +1187 -0
  24. package/labware/definitions/2/corning_12_wellplate_6.9ml_flat/4.json +210 -0
  25. package/labware/definitions/2/corning_24_wellplate_3.4ml_flat/4.json +342 -0
  26. package/labware/definitions/2/corning_48_wellplate_1.6ml_flat/5.json +610 -0
  27. package/labware/definitions/2/corning_6_wellplate_16.8ml_flat/4.json +134 -0
  28. package/labware/definitions/2/corning_96_wellplate_360ul_flat/4.json +1177 -0
  29. package/labware/definitions/2/corning_96_wellplate_360ul_lid/1.json +111 -0
  30. package/labware/definitions/2/ev_resin_tips_flex_96_labware/1.json +1 -1
  31. package/labware/definitions/2/ibidi_96_square_well_plate_300ul/1.json +1105 -0
  32. package/labware/definitions/2/ibidi_96_square_well_plate_300ul/2.json +1216 -0
  33. package/labware/definitions/2/ibidi_96_square_well_plate_300ul_lid/1.json +110 -0
  34. package/labware/definitions/2/nest_12_reservoir_22ml/1.json +232 -0
  35. package/labware/definitions/2/nest_24_wellplate_10.4ml/1.json +386 -0
  36. package/labware/definitions/2/nest_8_reservoir_22ml/1.json +162 -0
  37. package/labware/definitions/2/nest_96_wellplate_100ul_pcr_full_skirt/4.json +1166 -0
  38. package/labware/definitions/2/nest_96_wellplate_200ul_flat/4.json +1145 -0
  39. package/labware/definitions/2/nest_96_wellplate_2ml_deep/4.json +1261 -0
  40. package/labware/definitions/2/opentrons_96_wellplate_200ul_pcr_full_skirt/4.json +1174 -0
  41. package/labware/definitions/2/opentrons_flex_96_filtertiprack_1000ul/1.json +5 -0
  42. package/labware/definitions/2/opentrons_flex_96_filtertiprack_200ul/1.json +5 -0
  43. package/labware/definitions/2/opentrons_flex_96_filtertiprack_20ul/1.json +5 -0
  44. package/labware/definitions/2/opentrons_flex_96_filtertiprack_50ul/1.json +5 -0
  45. package/labware/definitions/2/opentrons_flex_96_tiprack_1000ul/1.json +5 -0
  46. package/labware/definitions/2/opentrons_flex_96_tiprack_200ul/1.json +5 -0
  47. package/labware/definitions/2/opentrons_flex_96_tiprack_20ul/1.json +5 -0
  48. package/labware/definitions/2/opentrons_flex_96_tiprack_50ul/1.json +5 -0
  49. package/labware/definitions/2/opentrons_flex_tiprack_lid/1.json +8 -8
  50. package/labware/definitions/2/opentrons_tough_pcr_auto_sealing_lid/1.json +8 -0
  51. package/labware/definitions/2/opentrons_tough_universal_lid/1.json +16 -1
  52. package/labware/definitions/2/smc_384_read_plate/1.json +4701 -0
  53. package/labware/definitions/2/smc_384_read_plate/2.json +5100 -0
  54. package/labware/definitions/2/thermoscientificnunc_96_wellplate_1300ul/3.json +1141 -0
  55. package/labware/definitions/2/thermoscientificnunc_96_wellplate_2000ul/3.json +1141 -0
  56. package/labware/definitions/2/usascientific_96_wellplate_2.4ml_deep/3.json +1243 -0
  57. package/labware/definitions/3/schema3test_96_well_aluminum_block/999.json +5 -2
  58. package/labware/definitions/3/schema3test_96_wellplate_200ul_pcr_full_skirt/999.json +15 -2
  59. package/labware/definitions/3/schema3test_aluminum_flat_bottom_plate/999.json +70 -0
  60. package/labware/definitions/3/schema3test_flex_96_tiprack_200ul/999.json +5 -9
  61. package/labware/definitions/3/schema3test_flex_96_tiprack_adapter/999.json +70 -0
  62. package/labware/definitions/3/schema3test_flex_tiprack_lid/999.json +146 -0
  63. package/labware/definitions/3/schema3test_tough_pcr_auto_sealing_lid/999.json +162 -0
  64. package/labware/definitions/3/schema3test_universal_flat_adapter/999.json +157 -0
  65. package/labware/fixtures/2/fixture_user_volumes_prototype.json +1137 -0
  66. package/labware/fixtures/3/fixture_2_plate.json +5 -2
  67. package/labware/fixtures/3/fixture_corning_24_plate.json +6 -3
  68. package/labware/fixtures/3/index.ts +4 -0
  69. package/labware/schemas/2.json +36 -1
  70. package/labware/schemas/3.json +57 -5
  71. package/lib/command/index.d.ts +39 -1
  72. package/lib/command/schemas/13.json +147 -315
  73. package/lib/command/schemas/14.json +7254 -0
  74. package/lib/command/types/index.d.ts +11 -3
  75. package/lib/command/types/module.d.ts +19 -6
  76. package/lib/command/types/setup.d.ts +5 -5
  77. package/lib/deck/definitions/5/ot2_short_trash.json +37 -0
  78. package/lib/deck/definitions/5/ot2_standard.json +37 -0
  79. package/lib/deck/definitions/5/ot3_standard.json +152 -51
  80. package/lib/deck/schemas/5.json +46 -1
  81. package/lib/index.mjs +240842 -193770
  82. package/lib/js/constants.d.ts +30 -9
  83. package/lib/js/fixtures.d.ts +77 -2
  84. package/lib/js/getLabware.d.ts +3 -3
  85. package/lib/js/helpers/__tests__/getMaxPushOutVolume.test.d.ts +1 -0
  86. package/lib/js/helpers/__tests__/getStackedItemsOnStartingDeck.test.d.ts +1 -0
  87. package/lib/js/helpers/__tests__/labwareSchemaShims.test.d.ts +1 -0
  88. package/lib/js/helpers/__tests__/pairsFromArray.test.d.ts +1 -0
  89. package/lib/js/helpers/__tests__/vectorMath.test.d.ts +1 -0
  90. package/lib/js/helpers/getFixedTrashLabwareDefinition.d.ts +2 -2
  91. package/lib/js/helpers/getLabwareDefURI.d.ts +3 -0
  92. package/lib/js/helpers/getLabwareDefinitionsByURIForProtocol.d.ts +6 -0
  93. package/lib/js/helpers/getLabwareInfoByLiquidId.d.ts +10 -0
  94. package/lib/js/helpers/getLiquidsByIdForLabware.d.ts +2 -0
  95. package/lib/js/helpers/getLoadedLabwareDefinitionsByUri.d.ts +2 -2
  96. package/lib/js/helpers/getMaxPushOutVolume.d.ts +2 -0
  97. package/lib/js/helpers/getStackedItemsOnStartingDeck.d.ts +50 -0
  98. package/lib/js/helpers/getStandardDeckViewLayerBlockList.d.ts +2 -0
  99. package/lib/js/helpers/getTipTypeFromTipRackDefinition.d.ts +2 -2
  100. package/lib/js/helpers/getWellFillFromLabwareId.d.ts +4 -0
  101. package/lib/js/helpers/getWellNamePerMultiTip.d.ts +3 -3
  102. package/lib/js/helpers/getWellTotalVolume.d.ts +2 -2
  103. package/lib/js/helpers/index.d.ts +22 -14
  104. package/lib/js/helpers/labwareInference.d.ts +3 -3
  105. package/lib/js/helpers/liquidClasses.d.ts +4 -2
  106. package/lib/js/helpers/matrixMath.d.ts +3 -0
  107. package/lib/js/helpers/pairsFromArray.d.ts +8 -0
  108. package/lib/js/helpers/parseProtocolCommands.d.ts +4 -4
  109. package/lib/js/helpers/positionMath.d.ts +127 -0
  110. package/lib/js/helpers/validateCustomLabwareHelper.d.ts +2 -2
  111. package/lib/js/helpers/vectorMath.d.ts +14 -0
  112. package/lib/js/helpers/wellSets.d.ts +4 -4
  113. package/lib/js/labware.d.ts +4 -3
  114. package/lib/js/liquidClasses.d.ts +4 -0
  115. package/lib/js/modules.d.ts +1 -1
  116. package/lib/js/types.d.ts +62 -13
  117. package/lib/labware/definitions/2/appliedbiosystemsmicroamp_384_wellplate_40ul/3.json +4737 -0
  118. package/lib/labware/definitions/2/axygen_96_wellplate_500ul/1.json +1036 -0
  119. package/lib/labware/definitions/2/axygen_96_wellplate_500ul/2.json +1159 -0
  120. package/lib/labware/definitions/2/biorad_384_wellplate_50ul/4.json +4748 -0
  121. package/lib/labware/definitions/2/biorad_96_wellplate_200ul_pcr/4.json +1187 -0
  122. package/lib/labware/definitions/2/corning_12_wellplate_6.9ml_flat/4.json +210 -0
  123. package/lib/labware/definitions/2/corning_24_wellplate_3.4ml_flat/4.json +342 -0
  124. package/lib/labware/definitions/2/corning_48_wellplate_1.6ml_flat/5.json +610 -0
  125. package/lib/labware/definitions/2/corning_6_wellplate_16.8ml_flat/4.json +134 -0
  126. package/lib/labware/definitions/2/corning_96_wellplate_360ul_flat/4.json +1177 -0
  127. package/lib/labware/definitions/2/corning_96_wellplate_360ul_lid/1.json +111 -0
  128. package/lib/labware/definitions/2/ev_resin_tips_flex_96_labware/1.json +1 -1
  129. package/lib/labware/definitions/2/ibidi_96_square_well_plate_300ul/1.json +1105 -0
  130. package/lib/labware/definitions/2/ibidi_96_square_well_plate_300ul/2.json +1216 -0
  131. package/lib/labware/definitions/2/ibidi_96_square_well_plate_300ul_lid/1.json +110 -0
  132. package/lib/labware/definitions/2/nest_12_reservoir_22ml/1.json +232 -0
  133. package/lib/labware/definitions/2/nest_24_wellplate_10.4ml/1.json +386 -0
  134. package/lib/labware/definitions/2/nest_8_reservoir_22ml/1.json +162 -0
  135. package/lib/labware/definitions/2/nest_96_wellplate_100ul_pcr_full_skirt/4.json +1166 -0
  136. package/lib/labware/definitions/2/nest_96_wellplate_200ul_flat/4.json +1145 -0
  137. package/lib/labware/definitions/2/nest_96_wellplate_2ml_deep/4.json +1261 -0
  138. package/lib/labware/definitions/2/opentrons_96_wellplate_200ul_pcr_full_skirt/4.json +1174 -0
  139. package/lib/labware/definitions/2/opentrons_flex_96_filtertiprack_1000ul/1.json +5 -0
  140. package/lib/labware/definitions/2/opentrons_flex_96_filtertiprack_200ul/1.json +5 -0
  141. package/lib/labware/definitions/2/opentrons_flex_96_filtertiprack_20ul/1.json +5 -0
  142. package/lib/labware/definitions/2/opentrons_flex_96_filtertiprack_50ul/1.json +5 -0
  143. package/lib/labware/definitions/2/opentrons_flex_96_tiprack_1000ul/1.json +5 -0
  144. package/lib/labware/definitions/2/opentrons_flex_96_tiprack_200ul/1.json +5 -0
  145. package/lib/labware/definitions/2/opentrons_flex_96_tiprack_20ul/1.json +5 -0
  146. package/lib/labware/definitions/2/opentrons_flex_96_tiprack_50ul/1.json +5 -0
  147. package/lib/labware/definitions/2/opentrons_flex_tiprack_lid/1.json +8 -8
  148. package/lib/labware/definitions/2/opentrons_tough_pcr_auto_sealing_lid/1.json +8 -0
  149. package/lib/labware/definitions/2/opentrons_tough_universal_lid/1.json +16 -1
  150. package/lib/labware/definitions/2/smc_384_read_plate/1.json +4701 -0
  151. package/lib/labware/definitions/2/smc_384_read_plate/2.json +5100 -0
  152. package/lib/labware/definitions/2/thermoscientificnunc_96_wellplate_1300ul/3.json +1141 -0
  153. package/lib/labware/definitions/2/thermoscientificnunc_96_wellplate_2000ul/3.json +1141 -0
  154. package/lib/labware/definitions/2/usascientific_96_wellplate_2.4ml_deep/3.json +1243 -0
  155. package/lib/labware/definitions/3/schema3test_96_well_aluminum_block/999.json +5 -2
  156. package/lib/labware/definitions/3/schema3test_96_wellplate_200ul_pcr_full_skirt/999.json +15 -2
  157. package/lib/labware/definitions/3/schema3test_aluminum_flat_bottom_plate/999.json +70 -0
  158. package/lib/labware/definitions/3/schema3test_flex_96_tiprack_200ul/999.json +5 -9
  159. package/lib/labware/definitions/3/schema3test_flex_96_tiprack_adapter/999.json +70 -0
  160. package/lib/labware/definitions/3/schema3test_flex_tiprack_lid/999.json +146 -0
  161. package/lib/labware/definitions/3/schema3test_tough_pcr_auto_sealing_lid/999.json +162 -0
  162. package/lib/labware/definitions/3/schema3test_universal_flat_adapter/999.json +157 -0
  163. package/lib/labware/fixtures/2/fixture_user_volumes_prototype.json +1137 -0
  164. package/lib/labware/fixtures/3/fixture_2_plate.json +5 -2
  165. package/lib/labware/fixtures/3/fixture_corning_24_plate.json +6 -3
  166. package/lib/labware/fixtures/3/index.d.ts +3 -0
  167. package/lib/labware/schemas/2.json +36 -1
  168. package/lib/labware/schemas/3.json +57 -5
  169. package/lib/liquid-class/definitions/1/{ethanol_80.json → ethanol_80/1.json} +545 -390
  170. package/lib/liquid-class/definitions/1/{glycerol_50.json → glycerol_50/1.json} +370 -215
  171. package/lib/liquid-class/definitions/1/{water.json → water/1.json} +151 -62
  172. package/lib/liquid-class/fixtures/1/fixture_glycerol50.json +1 -0
  173. package/lib/liquid-class/schemas/1.json +6 -0
  174. package/lib/module/definitions/3/absorbanceReaderV1.json +20 -151
  175. package/lib/module/definitions/3/flexStackerModuleV1.json +29 -389
  176. package/lib/module/definitions/3/heaterShakerModuleV1.json +16 -357
  177. package/lib/module/definitions/3/magneticBlockV1.json +18 -149
  178. package/lib/module/definitions/3/magneticModuleV1.json +16 -399
  179. package/lib/module/definitions/3/magneticModuleV2.json +16 -399
  180. package/lib/module/definitions/3/temperatureModuleV1.json +16 -153
  181. package/lib/module/definitions/3/temperatureModuleV2.json +16 -153
  182. package/lib/module/definitions/3/thermocyclerModuleV1.json +16 -1340
  183. package/lib/module/definitions/3/thermocyclerModuleV2.json +18 -3617
  184. package/lib/module/schemas/3.json +109 -12
  185. package/lib/pipette/definitions/1/pipetteModelSpecs.json +336 -0
  186. package/lib/pipette/definitions/2/general/ninety_six_channel/p200/3_2.json +660 -0
  187. package/lib/pipette/definitions/2/geometry/ninety_six_channel/p200/3_2.json +309 -0
  188. package/lib/pipette/definitions/2/liquid/ninety_six_channel/p200/default/3_1.json +28 -18
  189. package/lib/pipette/definitions/2/liquid/ninety_six_channel/p200/default/3_2.json +192 -0
  190. package/lib/protocol/types/schemaV8/index.d.ts +17 -1
  191. package/liquid-class/definitions/1/{ethanol_80.json → ethanol_80/1.json} +545 -390
  192. package/liquid-class/definitions/1/{glycerol_50.json → glycerol_50/1.json} +370 -215
  193. package/liquid-class/definitions/1/{water.json → water/1.json} +151 -62
  194. package/liquid-class/fixtures/1/fixture_glycerol50.json +1 -0
  195. package/liquid-class/schemas/1.json +6 -0
  196. package/module/definitions/3/absorbanceReaderV1.json +20 -151
  197. package/module/definitions/3/flexStackerModuleV1.json +29 -389
  198. package/module/definitions/3/heaterShakerModuleV1.json +16 -357
  199. package/module/definitions/3/magneticBlockV1.json +18 -149
  200. package/module/definitions/3/magneticModuleV1.json +16 -399
  201. package/module/definitions/3/magneticModuleV2.json +16 -399
  202. package/module/definitions/3/temperatureModuleV1.json +16 -153
  203. package/module/definitions/3/temperatureModuleV2.json +16 -153
  204. package/module/definitions/3/thermocyclerModuleV1.json +16 -1340
  205. package/module/definitions/3/thermocyclerModuleV2.json +18 -3617
  206. package/module/schemas/3.json +109 -12
  207. package/mypy.ini +22 -0
  208. package/package.json +1 -1
  209. package/pipette/definitions/1/pipetteModelSpecs.json +336 -0
  210. package/pipette/definitions/2/general/ninety_six_channel/p200/3_2.json +660 -0
  211. package/pipette/definitions/2/geometry/ninety_six_channel/p200/3_2.json +309 -0
  212. package/pipette/definitions/2/liquid/ninety_six_channel/p200/default/3_1.json +28 -18
  213. package/pipette/definitions/2/liquid/ninety_six_channel/p200/default/3_2.json +192 -0
  214. package/protocol/types/schemaV8/index.ts +29 -1
  215. package/pyproject.toml +119 -0
  216. package/pytest.ini +8 -0
  217. package/python_tests/__init__.py +1 -0
  218. package/python_tests/command/test_known_schema_ids.py +9 -0
  219. package/python_tests/conftest.py +108 -0
  220. package/python_tests/deck/__init__.py +0 -0
  221. package/python_tests/deck/test_list_names.py +12 -0
  222. package/python_tests/deck/test_position.py +101 -0
  223. package/python_tests/deck/test_typechecks.py +23 -0
  224. package/python_tests/errors/__init__.py +1 -0
  225. package/python_tests/errors/test_error_completeness.py +19 -0
  226. package/python_tests/errors/test_exceptions.py +74 -0
  227. package/python_tests/gripper/__init__.py +0 -0
  228. package/python_tests/gripper/test_definition.py +30 -0
  229. package/python_tests/gripper/test_load.py +19 -0
  230. package/python_tests/labware/__init__.py +13 -0
  231. package/python_tests/labware/test_typechecks.py +80 -0
  232. package/python_tests/liquid_classes/__init__.py +0 -0
  233. package/python_tests/liquid_classes/test_liquid_class_values.py +59 -0
  234. package/python_tests/liquid_classes/test_load.py +45 -0
  235. package/python_tests/liquid_classes/test_validations.py +192 -0
  236. package/python_tests/module/__init__.py +20 -0
  237. package/python_tests/module/test_load.py +49 -0
  238. package/python_tests/module/test_typechecks.py +26 -0
  239. package/python_tests/pipette/__init__.py +0 -0
  240. package/python_tests/pipette/test_load_data.py +109 -0
  241. package/python_tests/pipette/test_max_flow_rates_per_volume.py +112 -0
  242. package/python_tests/pipette/test_mutable_configurations.py +467 -0
  243. package/python_tests/pipette/test_pipette_definition.py +183 -0
  244. package/python_tests/pipette/test_pipette_load_name_conversions.py +244 -0
  245. package/python_tests/pipette/test_typechecks.py +47 -0
  246. package/python_tests/pipette/test_validate_schema.py +198 -0
  247. package/python_tests/protocol/__init__.py +7 -0
  248. package/python_tests/protocol/test_protocol_schema_v6.py +108 -0
  249. package/python_tests/protocol/test_protocol_schema_v7.py +35 -0
  250. package/python_tests/protocol/test_protocol_schema_v8.py +17 -0
  251. package/python_tests/protocol/test_typechecks.py +30 -0
  252. package/python_tests/robot/__init__.py +0 -0
  253. package/python_tests/robot/test_typechecks.py +13 -0
  254. package/lib/js/cypressUtils.d.ts +0 -1
  255. package/lib/js/helpers/getVectorDifference.d.ts +0 -2
  256. package/lib/js/helpers/getVectorSum.d.ts +0 -2
  257. /package/lib/js/{helpers/__tests__/getVectorDifference.test.d.ts → __tests__/fixtures.test.d.ts} +0 -0
  258. /package/lib/js/helpers/__tests__/{getVectorSum.test.d.ts → getLabwareInfoByLiquidId.test.d.ts} +0 -0
@@ -0,0 +1,59 @@
1
+ """Tests for the default values in built-in liquid class definitions."""
2
+ import pytest
3
+ from typing import List
4
+
5
+ from opentrons_shared_data import get_shared_data_root
6
+ from opentrons_shared_data.liquid_classes import load_definition
7
+
8
+
9
+ def _get_all_liquid_classes() -> List[str]:
10
+ return [
11
+ deffile.stem
12
+ for deffile in (
13
+ get_shared_data_root() / "liquid-class" / "definitions" / "1"
14
+ ).iterdir()
15
+ ]
16
+
17
+
18
+ @pytest.mark.parametrize("liquid_class_name", list(_get_all_liquid_classes()))
19
+ def test_correction_values_equal_each_other(liquid_class_name: str) -> None:
20
+ """The correction volume values for each pipette/tiprack combo should all be equal to one another."""
21
+ liquid_class_def = load_definition(liquid_class_name, version=1, schema_version=1)
22
+ incorrect_combos = []
23
+ for by_pipette in liquid_class_def.byPipette:
24
+ for liquid_class_props in by_pipette.byTipType:
25
+ if liquid_class_props.multiDispense is None:
26
+ continue
27
+ aspirate_correction = liquid_class_props.aspirate.correctionByVolume
28
+ dispense_correction = liquid_class_props.singleDispense.correctionByVolume
29
+ multi_dispense_correction = (
30
+ liquid_class_props.multiDispense.correctionByVolume
31
+ )
32
+ if (
33
+ aspirate_correction != dispense_correction
34
+ or dispense_correction != multi_dispense_correction
35
+ ):
36
+ incorrect_combos.append(
37
+ f"{by_pipette.pipetteModel} {liquid_class_props.tiprack}"
38
+ )
39
+ assert incorrect_combos == []
40
+
41
+
42
+ @pytest.mark.parametrize("liquid_class_name", list(_get_all_liquid_classes()))
43
+ def test_flow_rates_equal_each_other(liquid_class_name: str) -> None:
44
+ """The dispense flow rate values for each pipette/tiprack combo should all be equal to one another."""
45
+ liquid_class_def = load_definition(liquid_class_name, version=1, schema_version=1)
46
+ incorrect_combos = []
47
+ for by_pipette in liquid_class_def.byPipette:
48
+ for liquid_class_props in by_pipette.byTipType:
49
+ if liquid_class_props.multiDispense is None:
50
+ continue
51
+ dispense_flow_rates = liquid_class_props.singleDispense.flowRateByVolume
52
+ multi_dispense_flow_rates = (
53
+ liquid_class_props.multiDispense.flowRateByVolume
54
+ )
55
+ if dispense_flow_rates != multi_dispense_flow_rates:
56
+ incorrect_combos.append(
57
+ f"{by_pipette.pipetteModel} {liquid_class_props.tiprack}"
58
+ )
59
+ assert incorrect_combos == []
@@ -0,0 +1,45 @@
1
+ import json
2
+
3
+ from opentrons_shared_data import load_shared_data
4
+ from opentrons_shared_data.liquid_classes import load_definition, definition_exists
5
+ from opentrons_shared_data.liquid_classes.liquid_class_definition import (
6
+ LiquidClassSchemaV1,
7
+ PositionReference,
8
+ Coordinate,
9
+ TipPosition,
10
+ Submerge,
11
+ DelayParams,
12
+ DelayProperties,
13
+ )
14
+
15
+
16
+ def test_load_liquid_class_schema_v1() -> None:
17
+ fixture_data = load_shared_data("liquid-class/definitions/1/water/1.json")
18
+ liquid_class_model = LiquidClassSchemaV1.model_validate_json(fixture_data)
19
+ liquid_class_def_from_model = json.loads(
20
+ liquid_class_model.model_dump_json(exclude_unset=True)
21
+ )
22
+ expected_liquid_class_def = json.loads(fixture_data)
23
+ assert liquid_class_def_from_model == expected_liquid_class_def
24
+
25
+
26
+ def test_load_definition() -> None:
27
+ water_definition = load_definition(name="water", version=1, schema_version=1)
28
+ assert type(water_definition) is LiquidClassSchemaV1
29
+ assert water_definition.byPipette[0].pipetteModel == "flex_1channel_50"
30
+ assert water_definition.byPipette[0].byTipType[0].aspirate.submerge == Submerge(
31
+ startPosition=TipPosition(
32
+ positionReference=PositionReference.WELL_TOP,
33
+ offset=Coordinate(x=0, y=0, z=2),
34
+ ),
35
+ speed=100,
36
+ delay=DelayProperties(enable=False, params=DelayParams(duration=0)),
37
+ )
38
+
39
+
40
+ def test_definition_exists() -> None:
41
+ """Should return whether specified definition exists in shared data or not."""
42
+ assert definition_exists(name="water", version=1) is True
43
+ assert definition_exists(name="glycerol_50", version=1) is True
44
+ assert definition_exists(name="glycerol_oh_no", version=1) is False
45
+ assert definition_exists(name="glycerol_50", version=2) is False
@@ -0,0 +1,192 @@
1
+ """Tests that validate the built-in liquid class definitions."""
2
+ import pytest
3
+ from typing import List, Dict, Any
4
+
5
+ from opentrons_shared_data import get_shared_data_root
6
+ from opentrons_shared_data.liquid_classes import load_definition
7
+ from opentrons_shared_data.liquid_classes.liquid_class_definition import (
8
+ DelayProperties,
9
+ MixProperties,
10
+ TouchTipProperties,
11
+ BlowoutProperties,
12
+ BlowoutLocation,
13
+ AspirateProperties,
14
+ PositionReference,
15
+ SingleDispenseProperties,
16
+ MultiDispenseProperties,
17
+ TransferProperties,
18
+ )
19
+
20
+
21
+ def _get_all_liquid_classes() -> List[str]:
22
+ return [
23
+ deffile.stem
24
+ for deffile in (
25
+ get_shared_data_root() / "liquid-class" / "definitions" / "1"
26
+ ).iterdir()
27
+ ]
28
+
29
+
30
+ @pytest.mark.parametrize("liquid_class_name", list(_get_all_liquid_classes()))
31
+ def test_validate_unique_pipette_keys(liquid_class_name: str) -> None:
32
+ """A liquid class definition should contain only one set of properties per pipette model."""
33
+ definition_dict = load_definition(liquid_class_name, version=1, schema_version=1)
34
+ pipette_models = [prop.pipetteModel for prop in definition_dict.byPipette]
35
+ assert len(pipette_models) == len(set(pipette_models))
36
+
37
+
38
+ @pytest.mark.parametrize("liquid_class_name", list(_get_all_liquid_classes()))
39
+ def test_validate_unique_tip_keys(liquid_class_name: str) -> None:
40
+ """A liquid class definition should contain only one set of properties per tip type."""
41
+ definition_dict = load_definition(liquid_class_name, version=1, schema_version=1)
42
+
43
+ for by_pip_prop in definition_dict.byPipette:
44
+ tipracks = [tip_prop.tiprack for tip_prop in by_pip_prop.byTipType]
45
+ assert len(tipracks) == len(set(tipracks))
46
+
47
+
48
+ def test_validate_delay_properties_dict() -> None:
49
+ """Delay properties model validator should convert valid dict to DelayProperties."""
50
+ obj = DelayProperties.model_validate({"enable": True, "duration": 2})
51
+ assert isinstance(obj, DelayProperties)
52
+ assert obj.enable is True
53
+ assert obj.params.duration == 2 # type: ignore[union-attr]
54
+
55
+ with pytest.raises(
56
+ ValueError,
57
+ match="Delay properties should specify either duration or params, not both",
58
+ ):
59
+ DelayProperties.model_validate(
60
+ {"enable": False, "params": {"duration": 2}, "duration": 2}
61
+ )
62
+
63
+
64
+ def test_validate_mix_properties_dict() -> None:
65
+ """Mix properties model validator should convert valid dict to MixProperties."""
66
+ obj = MixProperties.model_validate({"enable": True, "repetitions": 2, "volume": 3})
67
+ assert isinstance(obj, MixProperties)
68
+ assert obj.enable is True
69
+ assert obj.params is not None
70
+ assert obj.params.repetitions == 2
71
+ assert obj.params.volume == 3
72
+
73
+ with pytest.raises(
74
+ ValueError,
75
+ match="either all of \\['repetitions', 'volume'\\] or 'params', not both",
76
+ ):
77
+ MixProperties.model_validate(
78
+ {"enable": True, "repetitions": 2, "volume": 3, "params": {"foo": "bar"}}
79
+ )
80
+
81
+
82
+ def test_validate_touchtip_properties_dict() -> None:
83
+ """Touch tip properties model validator should convert valid dict to TouchTipProperties."""
84
+ obj = TouchTipProperties.model_validate(
85
+ {"enable": True, "z_offset": 2, "mm_from_edge": 3, "speed": 4}
86
+ )
87
+ assert isinstance(obj, TouchTipProperties)
88
+ assert obj.enable is True
89
+ assert obj.params is not None
90
+ assert obj.params.mmFromEdge == 3
91
+ assert obj.params.speed == 4
92
+ assert obj.params.zOffset == 2
93
+
94
+ with pytest.raises(
95
+ ValueError,
96
+ match="either all of \\['z_offset', 'mm_from_edge', 'speed'\\] or 'params', not both",
97
+ ):
98
+ TouchTipProperties.model_validate(
99
+ {
100
+ "enable": True,
101
+ "z_offset": 2,
102
+ "mm_from_edge": 3,
103
+ "speed": 4,
104
+ "params": {"foo": "bar"},
105
+ }
106
+ )
107
+
108
+
109
+ def test_validate_blowout_properties_dict() -> None:
110
+ """Blowout properties model validator should convert valid dict to BlowoutProperties."""
111
+ obj = BlowoutProperties.model_validate(
112
+ {"enable": True, "location": "source", "flow_rate": 3}
113
+ )
114
+ assert isinstance(obj, BlowoutProperties)
115
+ assert obj.enable is True
116
+ assert obj.params is not None
117
+ assert obj.params.location == BlowoutLocation.SOURCE
118
+ assert obj.params.flowRate == 3
119
+
120
+ with pytest.raises(
121
+ ValueError,
122
+ match="either all of \\['location', 'flow_rate'\\] or 'params', not both",
123
+ ):
124
+ BlowoutProperties.model_validate(
125
+ {
126
+ "enable": True,
127
+ "location": "source",
128
+ "flow_rate": 3,
129
+ "params": {"foo": "bar"},
130
+ }
131
+ )
132
+
133
+
134
+ def test_validate_aspirate_properties_dict(
135
+ sample_transfer_properties_dict: Dict[str, Dict[str, Any]],
136
+ ) -> None:
137
+ """Aspirate properties model validator should convert valid dict to AspirateProperties."""
138
+ obj = AspirateProperties.model_validate(
139
+ sample_transfer_properties_dict["flex_1channel_50"][
140
+ "opentrons/opentrons_flex_96_tiprack_50ul/1"
141
+ ]["aspirate"]
142
+ )
143
+ assert isinstance(obj, AspirateProperties)
144
+ assert obj.aspiratePosition.positionReference == PositionReference.WELL_BOTTOM
145
+ assert obj.mix.enable is False
146
+
147
+
148
+ def test_validate_single_dispense_properties_dict(
149
+ sample_transfer_properties_dict: Dict[str, Dict[str, Any]],
150
+ ) -> None:
151
+ """Single dispense properties model validator should convert valid dict to SingleDispenseProperties."""
152
+ obj = SingleDispenseProperties.model_validate(
153
+ sample_transfer_properties_dict["flex_1channel_50"][
154
+ "opentrons/opentrons_flex_96_tiprack_50ul/1"
155
+ ]["dispense"]
156
+ )
157
+ assert isinstance(obj, SingleDispenseProperties)
158
+ assert obj.dispensePosition.positionReference == PositionReference.WELL_BOTTOM
159
+ assert obj.mix.enable is False
160
+
161
+
162
+ def test_validate_multi_dispense_properties_dict(
163
+ sample_transfer_properties_dict: Dict[str, Dict[str, Any]],
164
+ ) -> None:
165
+ """Multi dispense properties model validator should convert valid dict to MultiDispenseProperties."""
166
+ obj = MultiDispenseProperties.model_validate(
167
+ sample_transfer_properties_dict["flex_1channel_50"][
168
+ "opentrons/opentrons_flex_96_tiprack_50ul/1"
169
+ ]["multi_dispense"]
170
+ )
171
+ assert isinstance(obj, MultiDispenseProperties)
172
+ assert obj.dispensePosition.positionReference == PositionReference.WELL_BOTTOM
173
+ assert obj.conditioningByVolume == [(0, 0)]
174
+ assert obj.disposalByVolume == [(0, 5)]
175
+
176
+
177
+ def test_validate_transfer_properties_dict(
178
+ sample_transfer_properties_dict: Dict[str, Dict[str, Any]],
179
+ ) -> None:
180
+ """Transfer properties model validator should convert valid dict to TransferProperties."""
181
+ obj = TransferProperties.model_validate(
182
+ sample_transfer_properties_dict["flex_1channel_50"][
183
+ "opentrons/opentrons_flex_96_tiprack_50ul/1"
184
+ ]
185
+ )
186
+ assert isinstance(obj, TransferProperties)
187
+ assert (
188
+ obj.aspirate.aspiratePosition.positionReference == PositionReference.WELL_BOTTOM
189
+ )
190
+ assert obj.singleDispense.pushOutByVolume == [(10.0, 7.0), (20.0, 10.0)]
191
+ assert obj.multiDispense.conditioningByVolume == [(0, 0)] # type: ignore[union-attr]
192
+ assert obj.multiDispense.disposalByVolume == [(0, 5)] # type: ignore[union-attr]
@@ -0,0 +1,20 @@
1
+ from pathlib import Path
2
+ from typing import List
3
+
4
+
5
+ def list_v2_defs() -> List[str]:
6
+ return [
7
+ deffile.stem
8
+ for deffile in (
9
+ Path(__file__).parent / ".." / ".." / "module" / "definitions" / "2"
10
+ ).iterdir()
11
+ ]
12
+
13
+
14
+ def list_v3_defs() -> List[str]:
15
+ return [
16
+ deffile.stem
17
+ for deffile in (
18
+ Path(__file__).parent / ".." / ".." / "module" / "definitions" / "3"
19
+ ).iterdir()
20
+ ]
@@ -0,0 +1,49 @@
1
+ import json
2
+ import pytest
3
+
4
+ from opentrons_shared_data.module import (
5
+ load_definition,
6
+ load_schema,
7
+ ModuleNotFoundError,
8
+ )
9
+ from opentrons_shared_data import load_shared_data
10
+
11
+ from . import list_v2_defs, list_v3_defs
12
+
13
+
14
+ @pytest.mark.parametrize("def_name", list_v3_defs())
15
+ def test_load_v3_defs(def_name: str) -> None:
16
+ """Test that all v3 definitions load correctly."""
17
+ assert load_definition("3", def_name) == json.loads(
18
+ load_shared_data(f"module/definitions/3/{def_name}.json")
19
+ )
20
+
21
+
22
+ @pytest.mark.parametrize("def_name", list_v2_defs())
23
+ def test_load_v2_defs(def_name: str) -> None:
24
+ assert load_definition("2", def_name) == json.loads( # type: ignore [call-overload]
25
+ load_shared_data(f"module/definitions/2/{def_name}.json")
26
+ )
27
+
28
+
29
+ @pytest.mark.parametrize("def_name", ["magdeck", "tempdeck", "thermocycler"])
30
+ def test_load_v1_defs(def_name: str) -> None:
31
+ assert (
32
+ load_definition("1", def_name)
33
+ == json.loads(load_shared_data("module/definitions/1.json"))[def_name]
34
+ )
35
+
36
+
37
+ def test_bad_module_name_throws() -> None:
38
+ with pytest.raises(ModuleNotFoundError):
39
+ load_definition("1", "alsjdag")
40
+
41
+ with pytest.raises(ModuleNotFoundError):
42
+ load_definition("2", "asdasda") # type: ignore[call-overload]
43
+
44
+
45
+ @pytest.mark.parametrize("schema_name", ["1", "2", "3"])
46
+ def test_load_schema(schema_name: str) -> None:
47
+ assert load_schema(schema_name) == json.loads( # type: ignore[arg-type]
48
+ load_shared_data(f"module/schemas/{schema_name}.json")
49
+ )
@@ -0,0 +1,26 @@
1
+ import pytest
2
+ import typeguard
3
+
4
+ from opentrons_shared_data import module
5
+ from opentrons_shared_data.module import types
6
+
7
+ from . import list_v2_defs, list_v3_defs
8
+
9
+
10
+ @pytest.mark.parametrize("defname", list_v3_defs())
11
+ def test_v3_definitions_match_types(defname: str) -> None:
12
+ """Test that V3 module definitions match ModuleDefinitionV3."""
13
+ def_dict = module.load_definition("3", defname)
14
+ typeguard.check_type(def_dict, types.ModuleDefinitionV3)
15
+
16
+
17
+ @pytest.mark.parametrize("defname", list_v2_defs())
18
+ def test_v2_definitions_match_types(defname: str) -> None:
19
+ defdict = module.load_definition("2", defname) # type: ignore [call-overload]
20
+ typeguard.check_type(defdict, types.ModuleDefinitionV2)
21
+
22
+
23
+ @pytest.mark.parametrize("defname", ["magdeck", "tempdeck", "thermocycler"])
24
+ def test_v1_definitions_match_types(defname: str) -> None:
25
+ defdict = module.load_definition("1", defname)
26
+ typeguard.check_type(defdict, types.ModuleDefinitionV1)
File without changes
@@ -0,0 +1,109 @@
1
+ import pytest
2
+ from typing import Dict, Any, cast
3
+ from opentrons_shared_data.pipette import (
4
+ load_data,
5
+ pipette_load_name_conversions,
6
+ types,
7
+ )
8
+ from opentrons_shared_data.pipette.types import (
9
+ PipetteChannelType,
10
+ PipetteModelType,
11
+ PipetteVersionType,
12
+ PipetteOEMType,
13
+ PipetteTipType,
14
+ Quirks,
15
+ LiquidClasses,
16
+ )
17
+
18
+
19
+ def test_load_pipette_definition() -> None:
20
+ pipette_config_one = load_data.load_definition(
21
+ PipetteModelType.p50,
22
+ PipetteChannelType.SINGLE_CHANNEL,
23
+ PipetteVersionType(major=3, minor=3),
24
+ PipetteOEMType.OT,
25
+ )
26
+
27
+ assert pipette_config_one.channels == 1
28
+ assert pipette_config_one.pipette_type.value == "p50"
29
+ assert pipette_config_one.nozzle_offset == [-8.0, -22.0, -259.15]
30
+
31
+ assert (
32
+ pipette_config_one.liquid_properties[LiquidClasses.default]
33
+ .supported_tips[PipetteTipType.t50]
34
+ .default_aspirate_flowrate.default
35
+ == 8.0
36
+ )
37
+
38
+ assert pipette_config_one.quirks == []
39
+ pipette_config_two = load_data.load_definition(
40
+ PipetteModelType.p50,
41
+ PipetteChannelType.SINGLE_CHANNEL,
42
+ PipetteVersionType(major=1, minor=0),
43
+ PipetteOEMType.OT,
44
+ )
45
+
46
+ assert pipette_config_two.channels == 1
47
+ assert pipette_config_two.pipette_type.value == "p50"
48
+ assert pipette_config_two.nozzle_offset == [0.0, 0.0, 25.0]
49
+ assert (
50
+ pipette_config_two.liquid_properties[LiquidClasses.default]
51
+ .supported_tips[PipetteTipType.t200]
52
+ .default_aspirate_flowrate.default
53
+ == 25.0
54
+ )
55
+ assert pipette_config_two.quirks == [Quirks.dropTipShake]
56
+
57
+
58
+ @pytest.mark.parametrize(
59
+ argnames=["key_spot_check", "value_spot_check"],
60
+ argvalues=[
61
+ ["P1KSV10", "p1000_single_v1.0"],
62
+ ["P1KHV33", "p1000_96_v3.3"],
63
+ ["P20MV21", "p20_multi_v2.1"],
64
+ ["P300MV10", "p300_multi_v1.0"],
65
+ ["P3HMV14", "p300_multi_v1.4"],
66
+ ],
67
+ )
68
+ def test_build_serial_number_lookup(key_spot_check: str, value_spot_check: str) -> None:
69
+ lookup_table = load_data.load_serial_lookup_table()
70
+ assert lookup_table[key_spot_check] == value_spot_check
71
+
72
+
73
+ @pytest.mark.parametrize(
74
+ argnames=["pipette_model", "v1_configuration_changes"],
75
+ argvalues=[
76
+ ["p300_multi_v1.4", {"max_volume": 200, "min_volume": 10}],
77
+ ["p1000_96_v3.3", {"tip_length": 40, "min_volume": 300}],
78
+ ],
79
+ )
80
+ def test_update_pipette_configuration(
81
+ pipette_model: str, v1_configuration_changes: Dict[str, Any]
82
+ ) -> None:
83
+
84
+ liquid_class = LiquidClasses.default
85
+ model_name = pipette_load_name_conversions.convert_pipette_model(
86
+ cast(types.PipetteModel, pipette_model)
87
+ )
88
+ base_configurations = load_data.load_definition(
89
+ model_name.pipette_type,
90
+ model_name.pipette_channels,
91
+ model_name.pipette_version,
92
+ model_name.oem_type,
93
+ )
94
+
95
+ updated_configurations = load_data.update_pipette_configuration(
96
+ base_configurations, v1_configuration_changes, liquid_class
97
+ )
98
+
99
+ updated_configurations_dict = updated_configurations.model_dump()
100
+ for k, v in v1_configuration_changes.items():
101
+ if k == "tip_length":
102
+ for i in updated_configurations_dict["liquid_properties"][liquid_class][
103
+ "supported_tips"
104
+ ].values():
105
+ assert i["default_tip_length"] == v
106
+ else:
107
+ assert (
108
+ updated_configurations_dict["liquid_properties"][liquid_class][k] == v
109
+ )
@@ -0,0 +1,112 @@
1
+ import os
2
+ import pytest
3
+ from typing import Iterator
4
+ from opentrons_shared_data import get_shared_data_root
5
+ from opentrons_shared_data.pipette.pipette_load_name_conversions import (
6
+ convert_pipette_model,
7
+ )
8
+ from opentrons_shared_data.pipette.load_data import load_definition
9
+ from opentrons_shared_data.pipette.ul_per_mm import piecewise_volume_conversion
10
+
11
+ from opentrons_shared_data.pipette.types import PipetteModel
12
+ from opentrons_shared_data.pipette.pipette_definition import (
13
+ ulPerMMDefinition,
14
+ )
15
+
16
+
17
+ DEFAULT_MAX_SPEED_HIGH_THROUGHPUT_OT3_AXIS_KIND_P = 15
18
+ DEFAULT_MAX_SPEED_LOW_THROUGHPUT_OT3_AXIS_KIND_P = 70
19
+ B_MAX_SPEED = 40
20
+
21
+
22
+ def _get_plunger_max_speed(pipette_model: PipetteModel) -> float:
23
+ if "v2" in pipette_model:
24
+ return B_MAX_SPEED
25
+ else:
26
+ if "96" in pipette_model:
27
+ return DEFAULT_MAX_SPEED_HIGH_THROUGHPUT_OT3_AXIS_KIND_P
28
+ else:
29
+ return DEFAULT_MAX_SPEED_LOW_THROUGHPUT_OT3_AXIS_KIND_P
30
+
31
+
32
+ def _get_max_flow_rate_at_volume(
33
+ ul_per_mm_definition: ulPerMMDefinition,
34
+ pipette_model: PipetteModel,
35
+ volume: float,
36
+ ) -> float:
37
+ max_speed = _get_plunger_max_speed(pipette_model)
38
+ map = list(ul_per_mm_definition.default.values())[-1]
39
+ ul_per_mm = piecewise_volume_conversion(volume, map)
40
+ return round(ul_per_mm * max_speed, 1)
41
+
42
+
43
+ def get_all_pipette_models() -> Iterator[PipetteModel]:
44
+ paths_to_validate = (
45
+ get_shared_data_root() / "pipette" / "definitions" / "2" / "liquid"
46
+ )
47
+
48
+ _channel_model_str = {
49
+ "single_channel": "single",
50
+ "ninety_six_channel": "96",
51
+ "eight_channel": "multi",
52
+ "eight_channel_em": "multi_em",
53
+ }
54
+ assert os.listdir(paths_to_validate), "You have a path wrong"
55
+ for channel_dir in os.listdir(paths_to_validate):
56
+ for model_dir in os.listdir(paths_to_validate / channel_dir):
57
+ for liquid_file in os.listdir(paths_to_validate / channel_dir / model_dir):
58
+ for version_file in os.listdir(
59
+ paths_to_validate / channel_dir / model_dir / liquid_file
60
+ ):
61
+ version_list = version_file.split(".json")[0].split("_")
62
+ built_model: PipetteModel = PipetteModel(
63
+ f"{model_dir}_{_channel_model_str[channel_dir]}_v{version_list[0]}.{version_list[1]}"
64
+ )
65
+ if version_list[0] != "1" and version_list[1] != "0":
66
+ yield built_model
67
+
68
+
69
+ @pytest.mark.parametrize("pipette", list(get_all_pipette_models()))
70
+ @pytest.mark.parametrize("action", ["aspirate", "dispense"])
71
+ def test_max_flow_rates_per_volume(pipette: PipetteModel, action: str) -> None:
72
+ """Verify the max flow rate values for each pipette's supported tip is in range"""
73
+ pipette_model_version = convert_pipette_model(pipette)
74
+ definition = load_definition(
75
+ pipette_model_version.pipette_type,
76
+ pipette_model_version.pipette_channels,
77
+ pipette_model_version.pipette_version,
78
+ pipette_model_version.oem_type,
79
+ )
80
+
81
+ pipette_model_version_str = f"{pipette_model_version}"
82
+
83
+ for liquid_name, liquid_properties in definition.liquid_properties.items():
84
+ for tip_type, supported_tip in liquid_properties.supported_tips.items():
85
+
86
+ """TODO: the following models do not pass the asserts since the uiMaxFlowRate was raised
87
+ to match the default blowout and dispense flowRates. uiMaxFlowRate will be reevaluated
88
+ in the future."""
89
+ if not (
90
+ (
91
+ pipette_model_version_str
92
+ in {
93
+ "p50_single_v3.4",
94
+ "p50_single_v3.5",
95
+ "p50_single_v3.6",
96
+ "p50_multi_v3.5",
97
+ "p50_multi_v3.4",
98
+ }
99
+ and liquid_properties.min_volume == 5.0
100
+ )
101
+ or (
102
+ pipette_model_version_str
103
+ in {"p200_96_v3.0", "p200_96_v3.1", "p200_96_v3.2"}
104
+ and liquid_properties.min_volume == 0.5
105
+ )
106
+ ):
107
+ assert supported_tip.ui_max_flow_rate <= _get_max_flow_rate_at_volume(
108
+ supported_tip.aspirate, pipette, liquid_properties.min_volume
109
+ )
110
+ assert supported_tip.ui_max_flow_rate <= _get_max_flow_rate_at_volume(
111
+ supported_tip.dispense, pipette, liquid_properties.min_volume
112
+ )