opentrons 8.7.0a0__py3-none-any.whl → 8.7.0a1__py3-none-any.whl
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.
Potentially problematic release.
This version of opentrons might be problematic. Click here for more details.
- opentrons/_version.py +2 -2
- opentrons/protocol_api/core/engine/_default_liquid_class_versions.py +2 -0
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +77 -17
- opentrons/protocol_engine/state/geometry.py +33 -5
- opentrons/protocol_engine/state/modules.py +6 -0
- {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a1.dist-info}/METADATA +4 -4
- {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a1.dist-info}/RECORD +10 -10
- {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a1.dist-info}/WHEEL +0 -0
- {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a1.dist-info}/entry_points.txt +0 -0
- {opentrons-8.7.0a0.dist-info → opentrons-8.7.0a1.dist-info}/licenses/LICENSE +0 -0
opentrons/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '8.7.
|
|
32
|
-
__version_tuple__ = version_tuple = (8, 7, 0, '
|
|
31
|
+
__version__ = version = '8.7.0a1'
|
|
32
|
+
__version_tuple__ = version_tuple = (8, 7, 0, 'a1')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -21,7 +21,11 @@ from opentrons.protocol_engine import (
|
|
|
21
21
|
OnLabwareLocation,
|
|
22
22
|
DropTipWellLocation,
|
|
23
23
|
)
|
|
24
|
-
from opentrons.protocol_engine.types import
|
|
24
|
+
from opentrons.protocol_engine.types import (
|
|
25
|
+
StagingSlotLocation,
|
|
26
|
+
WellLocationType,
|
|
27
|
+
LoadedModule,
|
|
28
|
+
)
|
|
25
29
|
from opentrons.types import DeckSlotName, StagingSlotName, Point
|
|
26
30
|
from . import point_calculations
|
|
27
31
|
|
|
@@ -136,22 +140,47 @@ def check_safe_for_pipette_movement( # noqa: C901
|
|
|
136
140
|
f" will result in collision with thermocycler lid in deck slot A1."
|
|
137
141
|
)
|
|
138
142
|
|
|
143
|
+
def _check_for_column_4_module_collision(slot: DeckSlotName) -> None:
|
|
144
|
+
slot_module = engine_state.modules.get_by_slot(slot)
|
|
145
|
+
if (
|
|
146
|
+
slot_module
|
|
147
|
+
and engine_state.modules.is_column_4_module(slot_module.model)
|
|
148
|
+
and _slot_has_potential_colliding_object(
|
|
149
|
+
engine_state=engine_state,
|
|
150
|
+
pipette_bounds=pipette_bounds_at_well_location,
|
|
151
|
+
surrounding_location=slot_module,
|
|
152
|
+
)
|
|
153
|
+
):
|
|
154
|
+
raise PartialTipMovementNotAllowedError(
|
|
155
|
+
f"Moving to {engine_state.labware.get_display_name(labware_id)} in slot"
|
|
156
|
+
f" {slot} with {primary_nozzle} nozzle partial configuration will"
|
|
157
|
+
f" result in collision with items on {slot_module.model} mounted in {slot}."
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# We check the labware slot for a module that is mounted in the same cutout
|
|
161
|
+
# as the labwares slot but does not occupy the same heirarchy (like the stacker).
|
|
162
|
+
_check_for_column_4_module_collision(labware_slot)
|
|
163
|
+
|
|
139
164
|
for regular_slot in surrounding_slots.regular_slots:
|
|
140
165
|
if _slot_has_potential_colliding_object(
|
|
141
166
|
engine_state=engine_state,
|
|
142
167
|
pipette_bounds=pipette_bounds_at_well_location,
|
|
143
|
-
|
|
168
|
+
surrounding_location=regular_slot,
|
|
144
169
|
):
|
|
145
170
|
raise PartialTipMovementNotAllowedError(
|
|
146
171
|
f"Moving to {engine_state.labware.get_display_name(labware_id)} in slot"
|
|
147
172
|
f" {labware_slot} with {primary_nozzle} nozzle partial configuration"
|
|
148
173
|
f" will result in collision with items in deck slot {regular_slot}."
|
|
149
174
|
)
|
|
175
|
+
|
|
176
|
+
# Check for Column 4 Modules that may be descendants of a given surrounding slot
|
|
177
|
+
_check_for_column_4_module_collision(regular_slot)
|
|
178
|
+
|
|
150
179
|
for staging_slot in surrounding_slots.staging_slots:
|
|
151
180
|
if _slot_has_potential_colliding_object(
|
|
152
181
|
engine_state=engine_state,
|
|
153
182
|
pipette_bounds=pipette_bounds_at_well_location,
|
|
154
|
-
|
|
183
|
+
surrounding_location=staging_slot,
|
|
155
184
|
):
|
|
156
185
|
raise PartialTipMovementNotAllowedError(
|
|
157
186
|
f"Moving to {engine_state.labware.get_display_name(labware_id)} in slot"
|
|
@@ -178,18 +207,45 @@ def _get_critical_point_to_use(
|
|
|
178
207
|
def _slot_has_potential_colliding_object(
|
|
179
208
|
engine_state: StateView,
|
|
180
209
|
pipette_bounds: Tuple[Point, Point, Point, Point],
|
|
181
|
-
|
|
210
|
+
surrounding_location: Union[DeckSlotName, StagingSlotName, LoadedModule],
|
|
182
211
|
) -> bool:
|
|
183
|
-
"""Return the slot, if any, that has an item that the pipette might collide into.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
212
|
+
"""Return the slot, if any, that has an item that the pipette might collide into.
|
|
213
|
+
Can be provided a Deck Slot, Staging Slot, or Column 4 Module.
|
|
214
|
+
"""
|
|
215
|
+
if isinstance(surrounding_location, LoadedModule):
|
|
216
|
+
if (
|
|
217
|
+
engine_state.modules.is_column_4_module(surrounding_location.model)
|
|
218
|
+
and surrounding_location.location is not None
|
|
219
|
+
):
|
|
220
|
+
module_area = (
|
|
221
|
+
engine_state.modules.ensure_and_convert_module_fixture_location(
|
|
222
|
+
surrounding_location.location.slotName, surrounding_location.model
|
|
223
|
+
)
|
|
224
|
+
)
|
|
225
|
+
slot_pos = engine_state.addressable_areas.get_addressable_area_position(
|
|
226
|
+
addressable_area_name=module_area,
|
|
227
|
+
do_compatibility_check=False,
|
|
228
|
+
)
|
|
229
|
+
slot_bounds = (
|
|
230
|
+
engine_state.addressable_areas.get_addressable_area_bounding_box(
|
|
231
|
+
addressable_area_name=module_area,
|
|
232
|
+
do_compatibility_check=False,
|
|
233
|
+
)
|
|
234
|
+
)
|
|
235
|
+
else:
|
|
236
|
+
raise ValueError(
|
|
237
|
+
f"Error during collision validation, Module {surrounding_location.model} must be in Column 4."
|
|
238
|
+
)
|
|
239
|
+
else:
|
|
240
|
+
# Check if slot overlaps with pipette position
|
|
241
|
+
slot_pos = engine_state.addressable_areas.get_addressable_area_position(
|
|
242
|
+
addressable_area_name=surrounding_location.id,
|
|
243
|
+
do_compatibility_check=False,
|
|
244
|
+
)
|
|
245
|
+
slot_bounds = engine_state.addressable_areas.get_addressable_area_bounding_box(
|
|
246
|
+
addressable_area_name=surrounding_location.id,
|
|
247
|
+
do_compatibility_check=False,
|
|
248
|
+
)
|
|
193
249
|
slot_back_left_coords = Point(slot_pos.x, slot_pos.y + slot_bounds.y, slot_pos.z)
|
|
194
250
|
slot_front_right_coords = Point(slot_pos.x + slot_bounds.x, slot_pos.y, slot_pos.z)
|
|
195
251
|
|
|
@@ -199,13 +255,17 @@ def _slot_has_potential_colliding_object(
|
|
|
199
255
|
rectangle2=(slot_back_left_coords, slot_front_right_coords),
|
|
200
256
|
):
|
|
201
257
|
# Check z-height of items in overlapping slot
|
|
202
|
-
if isinstance(
|
|
258
|
+
if isinstance(surrounding_location, DeckSlotName):
|
|
203
259
|
slot_highest_z = engine_state.geometry.get_highest_z_in_slot(
|
|
204
|
-
DeckSlotLocation(slotName=
|
|
260
|
+
DeckSlotLocation(slotName=surrounding_location)
|
|
261
|
+
)
|
|
262
|
+
elif isinstance(surrounding_location, LoadedModule):
|
|
263
|
+
slot_highest_z = engine_state.geometry.get_highest_z_of_column_4_module(
|
|
264
|
+
surrounding_location
|
|
205
265
|
)
|
|
206
266
|
else:
|
|
207
267
|
slot_highest_z = engine_state.geometry.get_highest_z_in_slot(
|
|
208
|
-
StagingSlotLocation(slotName=
|
|
268
|
+
StagingSlotLocation(slotName=surrounding_location)
|
|
209
269
|
)
|
|
210
270
|
return slot_highest_z >= pipette_bounds[0].z
|
|
211
271
|
return False
|
|
@@ -274,12 +274,20 @@ class GeometryView:
|
|
|
274
274
|
try:
|
|
275
275
|
labware_id = self._labware.get_id_by_module(module_id=module_id)
|
|
276
276
|
except LabwareNotLoadedOnModuleError:
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
277
|
+
# For the time being we will ignore column 4 modules in this check to avoid conflating results
|
|
278
|
+
if self._modules.is_column_4_module(slot_item.model) is False:
|
|
279
|
+
return self._modules.get_module_highest_z(
|
|
280
|
+
module_id=module_id,
|
|
281
|
+
addressable_areas=self._addressable_areas,
|
|
282
|
+
)
|
|
281
283
|
else:
|
|
282
|
-
|
|
284
|
+
# For the time being we will ignore column 4 modules in this check to avoid conflating results
|
|
285
|
+
if self._modules.is_column_4_module(slot_item.model) is False:
|
|
286
|
+
return self.get_highest_z_of_labware_stack(labware_id)
|
|
287
|
+
# todo (cb, 2025-09-15): For now we skip column 4 modules and handle them seperately in
|
|
288
|
+
# get_highest_z_of_column_4_module, so this will return 0. In the future we may want to consolidate
|
|
289
|
+
# this to make it more apparently at this point in the query process.
|
|
290
|
+
return 0
|
|
283
291
|
elif isinstance(slot_item, LoadedLabware):
|
|
284
292
|
# get stacked heights of all labware in the slot
|
|
285
293
|
return self.get_highest_z_of_labware_stack(slot_item.id)
|
|
@@ -301,6 +309,26 @@ class GeometryView:
|
|
|
301
309
|
return self.get_labware_highest_z(labware_id)
|
|
302
310
|
return self.get_highest_z_of_labware_stack(stacked_labware_id)
|
|
303
311
|
|
|
312
|
+
def get_highest_z_of_column_4_module(self, module: LoadedModule) -> float:
|
|
313
|
+
"""Get the highest Z-point of the topmost labware in the stack of labware on the given column 4 module.
|
|
314
|
+
|
|
315
|
+
If there is no labware on the given module, returns highest z of the module.
|
|
316
|
+
"""
|
|
317
|
+
if self._modules.is_column_4_module(module.model):
|
|
318
|
+
try:
|
|
319
|
+
labware_id = self._labware.get_id_by_module(module_id=module.id)
|
|
320
|
+
except LabwareNotLoadedOnModuleError:
|
|
321
|
+
return self._modules.get_module_highest_z(
|
|
322
|
+
module_id=module.id,
|
|
323
|
+
addressable_areas=self._addressable_areas,
|
|
324
|
+
)
|
|
325
|
+
else:
|
|
326
|
+
return self.get_highest_z_of_labware_stack(labware_id)
|
|
327
|
+
else:
|
|
328
|
+
raise ValueError(
|
|
329
|
+
"Module must be a Column 4 Module to determine maximum z height."
|
|
330
|
+
)
|
|
331
|
+
|
|
304
332
|
def get_min_travel_z(
|
|
305
333
|
self,
|
|
306
334
|
pipette_id: str,
|
|
@@ -1330,6 +1330,12 @@ class ModuleView:
|
|
|
1330
1330
|
f"Module {module.model} is already present at {location}."
|
|
1331
1331
|
)
|
|
1332
1332
|
|
|
1333
|
+
def is_column_4_module(self, model: ModuleModel) -> bool:
|
|
1334
|
+
"""Determine whether or not a module is a Column 4 Module."""
|
|
1335
|
+
if model in _COLUMN_4_MODULES:
|
|
1336
|
+
return True
|
|
1337
|
+
return False
|
|
1338
|
+
|
|
1333
1339
|
def get_default_gripper_offsets(
|
|
1334
1340
|
self, module_id: str
|
|
1335
1341
|
) -> Optional[LabwareMovementOffsetData]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opentrons
|
|
3
|
-
Version: 8.7.
|
|
3
|
+
Version: 8.7.0a1
|
|
4
4
|
Summary: The Opentrons API is a simple framework designed to make writing automated biology lab protocols easy.
|
|
5
5
|
Project-URL: opentrons.com, https://www.opentrons.com
|
|
6
6
|
Project-URL: Source Code On Github, https://github.com/Opentrons/opentrons/tree/edge/api
|
|
@@ -24,7 +24,7 @@ Requires-Dist: click<9,>=8.0.0
|
|
|
24
24
|
Requires-Dist: importlib-metadata>=1.0; python_version < '3.8'
|
|
25
25
|
Requires-Dist: jsonschema<4.18.0,>=3.0.1
|
|
26
26
|
Requires-Dist: numpy<2,>=1.20.0
|
|
27
|
-
Requires-Dist: opentrons-shared-data==8.7.
|
|
27
|
+
Requires-Dist: opentrons-shared-data==8.7.0a1
|
|
28
28
|
Requires-Dist: packaging>=21.0
|
|
29
29
|
Requires-Dist: pydantic-settings<3,>=2
|
|
30
30
|
Requires-Dist: pydantic<3,>=2.0.0
|
|
@@ -32,6 +32,6 @@ Requires-Dist: pyserial>=3.5
|
|
|
32
32
|
Requires-Dist: pyusb==1.2.1
|
|
33
33
|
Requires-Dist: typing-extensions<5,>=4.0.0
|
|
34
34
|
Provides-Extra: flex-hardware
|
|
35
|
-
Requires-Dist: opentrons-hardware[flex]==8.7.
|
|
35
|
+
Requires-Dist: opentrons-hardware[flex]==8.7.0a1; extra == 'flex-hardware'
|
|
36
36
|
Provides-Extra: ot2-hardware
|
|
37
|
-
Requires-Dist: opentrons-hardware==8.7.
|
|
37
|
+
Requires-Dist: opentrons-hardware==8.7.0a1; extra == 'ot2-hardware'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
opentrons/__init__.py,sha256=TQ_Ca_zzAM3iLzAysWKkFkQHG8-imihxDPQbLCYrf-E,4533
|
|
2
|
-
opentrons/_version.py,sha256=
|
|
2
|
+
opentrons/_version.py,sha256=SN78vIsTT8t_rXBBup1Jg0Zmzddm97urqUZr263vZBg,712
|
|
3
3
|
opentrons/execute.py,sha256=Y88qICDiHWQjU0L4Ou7DI5OXXu7zZcdkUvNUYmZqIfc,29282
|
|
4
4
|
opentrons/legacy_broker.py,sha256=XnuEBBlrHCThc31RFW2UR0tGqctqWZ-CZ9vSC4L9whU,1553
|
|
5
5
|
opentrons/ordered_set.py,sha256=g-SB3qA14yxHu9zjGyc2wC7d2TUCBE6fKZlHAtbPzI8,4082
|
|
@@ -252,7 +252,7 @@ opentrons/protocol_api/core/well.py,sha256=Lf89YYEyq-ahRSRIFJw42vxIP8Fw6kzIUh9K1
|
|
|
252
252
|
opentrons/protocol_api/core/well_grid.py,sha256=BU28DKaBgEU_JdZ6pEzrwNxmuh6TkO4zlg7Pq1Rf5Xk,1516
|
|
253
253
|
opentrons/protocol_api/core/engine/__init__.py,sha256=B_5T7zgkWDb1mXPg4NbT-wBkQaK-WVokMMnJRNu7xiM,582
|
|
254
254
|
opentrons/protocol_api/core/engine/_default_labware_versions.py,sha256=hLKAp33c_eNLpvT5qUt8AOYy6PHhM_JnkdOXaMl80jA,7541
|
|
255
|
-
opentrons/protocol_api/core/engine/_default_liquid_class_versions.py,sha256=
|
|
255
|
+
opentrons/protocol_api/core/engine/_default_liquid_class_versions.py,sha256=be-eczhfOsWm4Q3fSVcjWqxteg_IGnwC-pozJUZ5u4U,1564
|
|
256
256
|
opentrons/protocol_api/core/engine/deck_conflict.py,sha256=j3AJ-sYr5e-06UgeGueUldx9B3fn7AhN738kJxZO_vw,14693
|
|
257
257
|
opentrons/protocol_api/core/engine/exceptions.py,sha256=aZgNrmYEeuPZm21nX_KZYtvyjv5h_zPjxxgPkEV7_bw,725
|
|
258
258
|
opentrons/protocol_api/core/engine/instrument.py,sha256=lDrCqOZm7ceu1E50EYiSh7qTDMci5cgw4bM-AvLyMjE,98890
|
|
@@ -260,7 +260,7 @@ opentrons/protocol_api/core/engine/labware.py,sha256=-2oygShyRZo1-R0UOoBtXniFOXf
|
|
|
260
260
|
opentrons/protocol_api/core/engine/load_labware_params.py,sha256=CxSbCBXVXHtBszP-3Ko8hsQTjvvogKRo0CCzCmMfIic,3003
|
|
261
261
|
opentrons/protocol_api/core/engine/module_core.py,sha256=qxxcqpH-A4Zil9hHDxnvh4H8JuPvK6-sgkODU5YdjZQ,39537
|
|
262
262
|
opentrons/protocol_api/core/engine/overlap_versions.py,sha256=PyGvQtQUg1wzNtkuGZtxwXm019PoIjq7em2JiWaxbXc,675
|
|
263
|
-
opentrons/protocol_api/core/engine/pipette_movement_conflict.py,sha256=
|
|
263
|
+
opentrons/protocol_api/core/engine/pipette_movement_conflict.py,sha256=9BmtG1kg3vyrssBXflCNZrJIukGp6y5UJ_XqhIz73rI,18148
|
|
264
264
|
opentrons/protocol_api/core/engine/point_calculations.py,sha256=C2eF0fvJQGMqQv3DzNhc1-m8HTAXTyTsHPJEPrEUEmo,2502
|
|
265
265
|
opentrons/protocol_api/core/engine/protocol.py,sha256=MQNMYNII1OxwaQGsKbOgVtmEH54mjDahzD-WHst9MH8,46247
|
|
266
266
|
opentrons/protocol_api/core/engine/robot.py,sha256=bzUt23NG-clD-9-QFsV_6nm3fMgSmvYEG9DyyZI1xgw,5366
|
|
@@ -462,12 +462,12 @@ opentrons/protocol_engine/state/commands.py,sha256=y5WE2pKmnMalgHFHEiBnBurO2TZ9w
|
|
|
462
462
|
opentrons/protocol_engine/state/config.py,sha256=7jSGxC6Vqj1eA8fqZ2I3zjlxVXg8pxvcBYMztRIx9Mg,1515
|
|
463
463
|
opentrons/protocol_engine/state/files.py,sha256=w8xxxg8HY0RqKKEGSfHWfrjV54Gb02O3dwtisJ-9j8E,1753
|
|
464
464
|
opentrons/protocol_engine/state/fluid_stack.py,sha256=uwkf0qYk1UX5iU52xmk-e3yLPK8OG-TtMCcBqrkVFpM,5932
|
|
465
|
-
opentrons/protocol_engine/state/geometry.py,sha256=
|
|
465
|
+
opentrons/protocol_engine/state/geometry.py,sha256=X-xyaF0orHMrNzZfzyGeOonazk0F67toJPbfGQmtmfM,105687
|
|
466
466
|
opentrons/protocol_engine/state/inner_well_math_utils.py,sha256=UhemsPpcuKwVc-iGXI2-v--miOGNunAnAVznJTVADlQ,20598
|
|
467
467
|
opentrons/protocol_engine/state/labware.py,sha256=vwagsqSBAIkVj4eupu0pIK6F3idnqqoRWDjVbp4ZwKQ,62977
|
|
468
468
|
opentrons/protocol_engine/state/liquid_classes.py,sha256=u_z75UYdiFAKG0yB3mr1il4T3qaS0Sotq8sL7KLODP8,2990
|
|
469
469
|
opentrons/protocol_engine/state/liquids.py,sha256=NoesktcQdJUjIVmet1uqqJPf-rzbo4SGemXwQC295W0,2338
|
|
470
|
-
opentrons/protocol_engine/state/modules.py,sha256=
|
|
470
|
+
opentrons/protocol_engine/state/modules.py,sha256=UbvbJcx45n5hZRbxQMTmxrA1rFichsWNUj6SpPAsBIU,61816
|
|
471
471
|
opentrons/protocol_engine/state/motion.py,sha256=pWt28-vBaO6dz_rtvoliUsGDvls_ML6sRfDOwmD0F7g,15086
|
|
472
472
|
opentrons/protocol_engine/state/pipettes.py,sha256=nXXQqeBIArPu0rEz-Y6OqA_F23A7uxPHVC2JfaJFH_g,38186
|
|
473
473
|
opentrons/protocol_engine/state/state.py,sha256=X8Sb2HN01nmNBY1Rw6qeLOjSuIWTbiq4g5otsd4u6A0,15600
|
|
@@ -595,8 +595,8 @@ opentrons/util/linal.py,sha256=IlKAP9HkNBBgULeSf4YVwSKHdx9jnCjSr7nvDvlRALg,5753
|
|
|
595
595
|
opentrons/util/logging_config.py,sha256=7et4YYuQdWdq_e50U-8vFS_QyNBRgdnqPGAQJm8qrIo,9954
|
|
596
596
|
opentrons/util/logging_queue_handler.py,sha256=ZsSJwy-oV8DXwpYiZisQ1PbYwmK2cOslD46AcyJ1E4I,2484
|
|
597
597
|
opentrons/util/performance_helpers.py,sha256=ew7H8XD20iS6-2TJAzbQeyzStZkkE6PzHt_Adx3wbZQ,5172
|
|
598
|
-
opentrons-8.7.
|
|
599
|
-
opentrons-8.7.
|
|
600
|
-
opentrons-8.7.
|
|
601
|
-
opentrons-8.7.
|
|
602
|
-
opentrons-8.7.
|
|
598
|
+
opentrons-8.7.0a1.dist-info/METADATA,sha256=VJsAOF5Ya8ZdUbGhic3GWkxexsL2BjOSVmMxJF3zeYY,1607
|
|
599
|
+
opentrons-8.7.0a1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
600
|
+
opentrons-8.7.0a1.dist-info/entry_points.txt,sha256=fTa6eGCYkvOtv0ov-KVE8LLGetgb35LQLF9x85OWPVw,106
|
|
601
|
+
opentrons-8.7.0a1.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
602
|
+
opentrons-8.7.0a1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|