opentrons 8.1.0__py2.py3-none-any.whl → 8.2.0__py2.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.
- opentrons/cli/analyze.py +71 -7
- opentrons/config/__init__.py +9 -0
- opentrons/config/advanced_settings.py +22 -0
- opentrons/config/defaults_ot3.py +14 -36
- opentrons/config/feature_flags.py +4 -0
- opentrons/config/types.py +6 -17
- opentrons/drivers/absorbance_reader/abstract.py +27 -3
- opentrons/drivers/absorbance_reader/async_byonoy.py +208 -154
- opentrons/drivers/absorbance_reader/driver.py +24 -15
- opentrons/drivers/absorbance_reader/hid_protocol.py +79 -50
- opentrons/drivers/absorbance_reader/simulator.py +32 -6
- opentrons/drivers/types.py +23 -1
- opentrons/execute.py +2 -2
- opentrons/hardware_control/api.py +18 -10
- opentrons/hardware_control/backends/controller.py +3 -2
- opentrons/hardware_control/backends/flex_protocol.py +11 -5
- opentrons/hardware_control/backends/ot3controller.py +18 -50
- opentrons/hardware_control/backends/ot3simulator.py +7 -6
- opentrons/hardware_control/backends/ot3utils.py +1 -0
- opentrons/hardware_control/instruments/ot2/pipette_handler.py +22 -82
- opentrons/hardware_control/instruments/ot3/pipette_handler.py +10 -2
- opentrons/hardware_control/module_control.py +43 -2
- opentrons/hardware_control/modules/__init__.py +7 -1
- opentrons/hardware_control/modules/absorbance_reader.py +232 -83
- opentrons/hardware_control/modules/errors.py +7 -0
- opentrons/hardware_control/modules/heater_shaker.py +8 -3
- opentrons/hardware_control/modules/magdeck.py +12 -3
- opentrons/hardware_control/modules/mod_abc.py +27 -2
- opentrons/hardware_control/modules/tempdeck.py +15 -7
- opentrons/hardware_control/modules/thermocycler.py +69 -3
- opentrons/hardware_control/modules/types.py +11 -5
- opentrons/hardware_control/modules/update.py +11 -5
- opentrons/hardware_control/modules/utils.py +3 -1
- opentrons/hardware_control/ot3_calibration.py +6 -6
- opentrons/hardware_control/ot3api.py +131 -94
- opentrons/hardware_control/poller.py +15 -11
- opentrons/hardware_control/protocols/__init__.py +1 -7
- opentrons/hardware_control/protocols/instrument_configurer.py +14 -2
- opentrons/hardware_control/protocols/liquid_handler.py +5 -0
- opentrons/hardware_control/protocols/position_estimator.py +3 -1
- opentrons/hardware_control/types.py +2 -0
- opentrons/legacy_commands/helpers.py +8 -2
- opentrons/motion_planning/__init__.py +2 -0
- opentrons/motion_planning/waypoints.py +32 -0
- opentrons/protocol_api/__init__.py +2 -1
- opentrons/protocol_api/_liquid.py +87 -1
- opentrons/protocol_api/_parameter_context.py +10 -1
- opentrons/protocol_api/core/engine/deck_conflict.py +0 -297
- opentrons/protocol_api/core/engine/instrument.py +29 -25
- opentrons/protocol_api/core/engine/labware.py +20 -4
- opentrons/protocol_api/core/engine/module_core.py +166 -17
- opentrons/protocol_api/core/engine/pipette_movement_conflict.py +362 -0
- opentrons/protocol_api/core/engine/protocol.py +30 -2
- opentrons/protocol_api/core/instrument.py +2 -0
- opentrons/protocol_api/core/labware.py +4 -0
- opentrons/protocol_api/core/legacy/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/legacy/legacy_labware_core.py +5 -0
- opentrons/protocol_api/core/legacy/legacy_protocol_core.py +6 -2
- opentrons/protocol_api/core/legacy_simulator/legacy_instrument_core.py +2 -0
- opentrons/protocol_api/core/module.py +22 -4
- opentrons/protocol_api/core/protocol.py +6 -2
- opentrons/protocol_api/instrument_context.py +52 -20
- opentrons/protocol_api/labware.py +13 -1
- opentrons/protocol_api/module_contexts.py +115 -17
- opentrons/protocol_api/protocol_context.py +49 -5
- opentrons/protocol_api/validation.py +5 -3
- opentrons/protocol_engine/__init__.py +10 -9
- opentrons/protocol_engine/actions/__init__.py +3 -0
- opentrons/protocol_engine/actions/actions.py +30 -25
- opentrons/protocol_engine/actions/get_state_update.py +38 -0
- opentrons/protocol_engine/clients/sync_client.py +1 -1
- opentrons/protocol_engine/clients/transports.py +1 -1
- opentrons/protocol_engine/commands/__init__.py +0 -4
- opentrons/protocol_engine/commands/absorbance_reader/__init__.py +41 -11
- opentrons/protocol_engine/commands/absorbance_reader/close_lid.py +148 -0
- opentrons/protocol_engine/commands/absorbance_reader/initialize.py +65 -9
- opentrons/protocol_engine/commands/absorbance_reader/open_lid.py +148 -0
- opentrons/protocol_engine/commands/absorbance_reader/read.py +200 -0
- opentrons/protocol_engine/commands/aspirate.py +29 -16
- opentrons/protocol_engine/commands/aspirate_in_place.py +33 -16
- opentrons/protocol_engine/commands/blow_out.py +63 -14
- opentrons/protocol_engine/commands/blow_out_in_place.py +55 -13
- opentrons/protocol_engine/commands/calibration/calibrate_gripper.py +2 -5
- opentrons/protocol_engine/commands/calibration/calibrate_module.py +3 -4
- opentrons/protocol_engine/commands/calibration/calibrate_pipette.py +2 -5
- opentrons/protocol_engine/commands/calibration/move_to_maintenance_position.py +6 -4
- opentrons/protocol_engine/commands/command.py +31 -18
- opentrons/protocol_engine/commands/command_unions.py +37 -24
- opentrons/protocol_engine/commands/comment.py +5 -3
- opentrons/protocol_engine/commands/configure_for_volume.py +11 -14
- opentrons/protocol_engine/commands/configure_nozzle_layout.py +9 -15
- opentrons/protocol_engine/commands/custom.py +5 -3
- opentrons/protocol_engine/commands/dispense.py +42 -20
- opentrons/protocol_engine/commands/dispense_in_place.py +32 -14
- opentrons/protocol_engine/commands/drop_tip.py +70 -16
- opentrons/protocol_engine/commands/drop_tip_in_place.py +59 -13
- opentrons/protocol_engine/commands/get_tip_presence.py +5 -3
- opentrons/protocol_engine/commands/heater_shaker/close_labware_latch.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_heater.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/deactivate_shaker.py +6 -6
- opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +8 -6
- opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +8 -4
- opentrons/protocol_engine/commands/heater_shaker/set_target_temperature.py +6 -4
- opentrons/protocol_engine/commands/heater_shaker/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/home.py +11 -5
- opentrons/protocol_engine/commands/liquid_probe.py +146 -88
- opentrons/protocol_engine/commands/load_labware.py +28 -5
- opentrons/protocol_engine/commands/load_liquid.py +18 -7
- opentrons/protocol_engine/commands/load_module.py +4 -6
- opentrons/protocol_engine/commands/load_pipette.py +18 -17
- opentrons/protocol_engine/commands/magnetic_module/disengage.py +6 -6
- opentrons/protocol_engine/commands/magnetic_module/engage.py +6 -4
- opentrons/protocol_engine/commands/move_labware.py +155 -23
- opentrons/protocol_engine/commands/move_relative.py +15 -3
- opentrons/protocol_engine/commands/move_to_addressable_area.py +29 -4
- opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +13 -4
- opentrons/protocol_engine/commands/move_to_coordinates.py +11 -5
- opentrons/protocol_engine/commands/move_to_well.py +37 -10
- opentrons/protocol_engine/commands/pick_up_tip.py +51 -30
- opentrons/protocol_engine/commands/pipetting_common.py +47 -16
- opentrons/protocol_engine/commands/prepare_to_aspirate.py +62 -15
- opentrons/protocol_engine/commands/reload_labware.py +13 -4
- opentrons/protocol_engine/commands/retract_axis.py +6 -3
- opentrons/protocol_engine/commands/save_position.py +2 -3
- opentrons/protocol_engine/commands/set_rail_lights.py +5 -3
- opentrons/protocol_engine/commands/set_status_bar.py +5 -3
- opentrons/protocol_engine/commands/temperature_module/deactivate.py +6 -4
- opentrons/protocol_engine/commands/temperature_module/set_target_temperature.py +3 -4
- opentrons/protocol_engine/commands/temperature_module/wait_for_temperature.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/__init__.py +19 -0
- opentrons/protocol_engine/commands/thermocycler/close_lid.py +8 -8
- opentrons/protocol_engine/commands/thermocycler/deactivate_block.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/deactivate_lid.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/open_lid.py +8 -4
- opentrons/protocol_engine/commands/thermocycler/run_extended_profile.py +165 -0
- opentrons/protocol_engine/commands/thermocycler/run_profile.py +6 -6
- opentrons/protocol_engine/commands/thermocycler/set_target_block_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/set_target_lid_temperature.py +3 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_block_temperature.py +6 -4
- opentrons/protocol_engine/commands/thermocycler/wait_for_lid_temperature.py +6 -4
- opentrons/protocol_engine/commands/touch_tip.py +19 -7
- opentrons/protocol_engine/commands/unsafe/__init__.py +30 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_blow_out_in_place.py +6 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_drop_tip_in_place.py +12 -4
- opentrons/protocol_engine/commands/unsafe/unsafe_engage_axes.py +5 -3
- opentrons/protocol_engine/commands/unsafe/unsafe_place_labware.py +208 -0
- opentrons/protocol_engine/commands/unsafe/unsafe_ungrip_labware.py +77 -0
- opentrons/protocol_engine/commands/unsafe/update_position_estimators.py +10 -4
- opentrons/protocol_engine/commands/verify_tip_presence.py +5 -5
- opentrons/protocol_engine/commands/wait_for_duration.py +5 -3
- opentrons/protocol_engine/commands/wait_for_resume.py +5 -3
- opentrons/protocol_engine/create_protocol_engine.py +60 -10
- opentrons/protocol_engine/engine_support.py +2 -1
- opentrons/protocol_engine/error_recovery_policy.py +14 -3
- opentrons/protocol_engine/errors/__init__.py +20 -0
- opentrons/protocol_engine/errors/error_occurrence.py +8 -3
- opentrons/protocol_engine/errors/exceptions.py +127 -2
- opentrons/protocol_engine/execution/__init__.py +2 -0
- opentrons/protocol_engine/execution/command_executor.py +22 -13
- opentrons/protocol_engine/execution/create_queue_worker.py +5 -1
- opentrons/protocol_engine/execution/door_watcher.py +1 -1
- opentrons/protocol_engine/execution/equipment.py +2 -1
- opentrons/protocol_engine/execution/error_recovery_hardware_state_synchronizer.py +101 -0
- opentrons/protocol_engine/execution/gantry_mover.py +4 -2
- opentrons/protocol_engine/execution/hardware_stopper.py +3 -3
- opentrons/protocol_engine/execution/heater_shaker_movement_flagger.py +1 -4
- opentrons/protocol_engine/execution/labware_movement.py +73 -22
- opentrons/protocol_engine/execution/movement.py +17 -7
- opentrons/protocol_engine/execution/pipetting.py +7 -4
- opentrons/protocol_engine/execution/queue_worker.py +6 -2
- opentrons/protocol_engine/execution/run_control.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_movement_flagger.py +1 -1
- opentrons/protocol_engine/execution/thermocycler_plate_lifter.py +2 -1
- opentrons/protocol_engine/execution/tip_handler.py +77 -43
- opentrons/protocol_engine/notes/__init__.py +14 -2
- opentrons/protocol_engine/notes/notes.py +18 -1
- opentrons/protocol_engine/plugins.py +1 -1
- opentrons/protocol_engine/protocol_engine.py +47 -31
- opentrons/protocol_engine/resources/__init__.py +2 -0
- opentrons/protocol_engine/resources/deck_data_provider.py +19 -5
- opentrons/protocol_engine/resources/file_provider.py +161 -0
- opentrons/protocol_engine/resources/fixture_validation.py +11 -1
- opentrons/protocol_engine/resources/labware_validation.py +10 -0
- opentrons/protocol_engine/state/__init__.py +0 -70
- opentrons/protocol_engine/state/addressable_areas.py +1 -1
- opentrons/protocol_engine/state/command_history.py +21 -2
- opentrons/protocol_engine/state/commands.py +110 -31
- opentrons/protocol_engine/state/files.py +59 -0
- opentrons/protocol_engine/state/frustum_helpers.py +440 -0
- opentrons/protocol_engine/state/geometry.py +445 -59
- opentrons/protocol_engine/state/labware.py +264 -84
- opentrons/protocol_engine/state/liquids.py +1 -1
- opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +21 -3
- opentrons/protocol_engine/state/modules.py +145 -90
- opentrons/protocol_engine/state/motion.py +33 -14
- opentrons/protocol_engine/state/pipettes.py +157 -317
- opentrons/protocol_engine/state/state.py +30 -1
- opentrons/protocol_engine/state/state_summary.py +3 -0
- opentrons/protocol_engine/state/tips.py +69 -114
- opentrons/protocol_engine/state/update_types.py +424 -0
- opentrons/protocol_engine/state/wells.py +236 -0
- opentrons/protocol_engine/types.py +90 -0
- opentrons/protocol_reader/file_format_validator.py +83 -15
- opentrons/protocol_runner/json_translator.py +21 -5
- opentrons/protocol_runner/legacy_command_mapper.py +27 -6
- opentrons/protocol_runner/legacy_context_plugin.py +27 -71
- opentrons/protocol_runner/protocol_runner.py +6 -3
- opentrons/protocol_runner/run_orchestrator.py +41 -6
- opentrons/protocols/advanced_control/mix.py +3 -5
- opentrons/protocols/advanced_control/transfers.py +125 -56
- opentrons/protocols/api_support/constants.py +1 -1
- opentrons/protocols/api_support/definitions.py +1 -1
- opentrons/protocols/api_support/labware_like.py +4 -4
- opentrons/protocols/api_support/tip_tracker.py +2 -2
- opentrons/protocols/api_support/types.py +15 -2
- opentrons/protocols/api_support/util.py +30 -42
- opentrons/protocols/duration/errors.py +1 -1
- opentrons/protocols/duration/estimator.py +50 -29
- opentrons/protocols/execution/dev_types.py +2 -2
- opentrons/protocols/execution/execute_json_v4.py +15 -10
- opentrons/protocols/execution/execute_python.py +8 -3
- opentrons/protocols/geometry/planning.py +12 -12
- opentrons/protocols/labware.py +17 -33
- opentrons/protocols/parameters/csv_parameter_interface.py +3 -1
- opentrons/simulate.py +3 -3
- opentrons/types.py +30 -3
- opentrons/util/logging_config.py +34 -0
- {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/METADATA +5 -4
- {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/RECORD +235 -223
- opentrons/protocol_engine/commands/absorbance_reader/measure.py +0 -94
- opentrons/protocol_engine/commands/configuring_common.py +0 -26
- opentrons/protocol_runner/thread_async_queue.py +0 -174
- /opentrons/protocol_engine/state/{abstract_store.py → _abstract_store.py} +0 -0
- /opentrons/protocol_engine/state/{move_types.py → _move_types.py} +0 -0
- {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/LICENSE +0 -0
- {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/WHEEL +0 -0
- {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/entry_points.txt +0 -0
- {opentrons-8.1.0.dist-info → opentrons-8.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"""Command models to measure absorbance."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
from typing import List, Optional, TYPE_CHECKING
|
|
4
|
-
from typing_extensions import Literal, Type
|
|
5
|
-
|
|
6
|
-
from pydantic import BaseModel, Field
|
|
7
|
-
|
|
8
|
-
from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData
|
|
9
|
-
from ...errors.error_occurrence import ErrorOccurrence
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from opentrons.protocol_engine.state import StateView
|
|
13
|
-
from opentrons.protocol_engine.execution import EquipmentHandler
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
MeasureAbsorbanceCommandType = Literal["absorbanceReader/measure"]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class MeasureAbsorbanceParams(BaseModel):
|
|
20
|
-
"""Input parameters for a single absorbance reading."""
|
|
21
|
-
|
|
22
|
-
moduleId: str = Field(..., description="Unique ID of the Absorbance Reader.")
|
|
23
|
-
sampleWavelength: int = Field(..., description="Sample wavelength in nm.")
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class MeasureAbsorbanceResult(BaseModel):
|
|
27
|
-
"""Result data from running an aborbance reading."""
|
|
28
|
-
|
|
29
|
-
# TODO: Transform this into a more complex model, such as a map with well names.
|
|
30
|
-
data: Optional[List[float]] = Field(
|
|
31
|
-
..., min_items=96, max_items=96, description="Absorbance data points."
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class MeasureAbsorbanceImpl(
|
|
36
|
-
AbstractCommandImpl[
|
|
37
|
-
MeasureAbsorbanceParams, SuccessData[MeasureAbsorbanceResult, None]
|
|
38
|
-
]
|
|
39
|
-
):
|
|
40
|
-
"""Execution implementation of an Absorbance Reader measurement."""
|
|
41
|
-
|
|
42
|
-
def __init__(
|
|
43
|
-
self,
|
|
44
|
-
state_view: StateView,
|
|
45
|
-
equipment: EquipmentHandler,
|
|
46
|
-
**unused_dependencies: object,
|
|
47
|
-
) -> None:
|
|
48
|
-
self._state_view = state_view
|
|
49
|
-
self._equipment = equipment
|
|
50
|
-
|
|
51
|
-
async def execute(
|
|
52
|
-
self, params: MeasureAbsorbanceParams
|
|
53
|
-
) -> SuccessData[MeasureAbsorbanceResult, None]:
|
|
54
|
-
"""Initiate a single absorbance measurement."""
|
|
55
|
-
abs_reader_substate = self._state_view.modules.get_absorbance_reader_substate(
|
|
56
|
-
module_id=params.moduleId
|
|
57
|
-
)
|
|
58
|
-
# Allow propagation of ModuleNotAttachedError.
|
|
59
|
-
abs_reader = self._equipment.get_module_hardware_api(
|
|
60
|
-
abs_reader_substate.module_id
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
if abs_reader is not None:
|
|
64
|
-
result = await abs_reader.start_measure(wavelength=params.sampleWavelength)
|
|
65
|
-
return SuccessData(
|
|
66
|
-
public=MeasureAbsorbanceResult(data=result),
|
|
67
|
-
private=None,
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
return SuccessData(
|
|
71
|
-
public=MeasureAbsorbanceResult(data=None),
|
|
72
|
-
private=None,
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
class MeasureAbsorbance(
|
|
77
|
-
BaseCommand[MeasureAbsorbanceParams, MeasureAbsorbanceResult, ErrorOccurrence]
|
|
78
|
-
):
|
|
79
|
-
"""A command to execute an Absorbance Reader measurement."""
|
|
80
|
-
|
|
81
|
-
commandType: MeasureAbsorbanceCommandType = "absorbanceReader/measure"
|
|
82
|
-
params: MeasureAbsorbanceParams
|
|
83
|
-
result: Optional[MeasureAbsorbanceResult]
|
|
84
|
-
|
|
85
|
-
_ImplementationCls: Type[MeasureAbsorbanceImpl] = MeasureAbsorbanceImpl
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
class MeasureAbsorbanceCreate(BaseCommandCreate[MeasureAbsorbanceParams]):
|
|
89
|
-
"""A request to execute an Absorbance Reader measurement."""
|
|
90
|
-
|
|
91
|
-
commandType: MeasureAbsorbanceCommandType = "absorbanceReader/measure"
|
|
92
|
-
params: MeasureAbsorbanceParams
|
|
93
|
-
|
|
94
|
-
_CommandCls: Type[MeasureAbsorbance] = MeasureAbsorbance
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"""Common configuration command base models."""
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from opentrons.hardware_control.nozzle_manager import (
|
|
5
|
-
NozzleMap,
|
|
6
|
-
)
|
|
7
|
-
from ..resources import pipette_data_provider
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@dataclass
|
|
11
|
-
class PipetteConfigUpdateResultMixin:
|
|
12
|
-
"""A mixin-suitable model for adding pipette config to private results."""
|
|
13
|
-
|
|
14
|
-
pipette_id: str
|
|
15
|
-
serial_number: str
|
|
16
|
-
config: pipette_data_provider.LoadedStaticPipetteData
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@dataclass
|
|
20
|
-
class PipetteNozzleLayoutResultMixin:
|
|
21
|
-
"""A nozzle layout result for updating the pipette state."""
|
|
22
|
-
|
|
23
|
-
pipette_id: str
|
|
24
|
-
|
|
25
|
-
nozzle_map: NozzleMap
|
|
26
|
-
"""A dataclass object holding information about the current nozzle configuration."""
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
"""Safely pass values between threads and async tasks."""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from __future__ import annotations
|
|
5
|
-
|
|
6
|
-
from collections import deque
|
|
7
|
-
from threading import Condition
|
|
8
|
-
from typing import AsyncIterable, Deque, Generic, Iterable, TypeVar
|
|
9
|
-
|
|
10
|
-
from anyio.to_thread import run_sync
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
_T = TypeVar("_T")
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class ThreadAsyncQueue(Generic[_T]):
|
|
17
|
-
"""A queue to safely pass values of type `_T` between threads and async tasks.
|
|
18
|
-
|
|
19
|
-
All methods are safe to call concurrently from any thread or task.
|
|
20
|
-
|
|
21
|
-
Compared to queue.Queue:
|
|
22
|
-
|
|
23
|
-
* This class lets you close the queue to signal that no more values will be added,
|
|
24
|
-
which makes common producer/consumer patterns easier.
|
|
25
|
-
(This is like Golang channels and AnyIO memory object streams.)
|
|
26
|
-
* This class has built-in support for async consumers.
|
|
27
|
-
|
|
28
|
-
Compared to asyncio.Queue and AnyIO memory object streams:
|
|
29
|
-
|
|
30
|
-
* You can use this class to communicate between async tasks and threads
|
|
31
|
-
without the threads having to wait for the event loop to be free
|
|
32
|
-
every time they access the queue.
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
def __init__(self) -> None:
|
|
36
|
-
"""Initialize the queue."""
|
|
37
|
-
self._is_closed = False
|
|
38
|
-
self._deque: Deque[_T] = deque()
|
|
39
|
-
self._condition = Condition()
|
|
40
|
-
|
|
41
|
-
def put(self, value: _T) -> None:
|
|
42
|
-
"""Add a value to the back of the queue.
|
|
43
|
-
|
|
44
|
-
Returns immediately, without blocking. The queue can grow without bound.
|
|
45
|
-
|
|
46
|
-
Raises:
|
|
47
|
-
QueueClosed: If the queue is already closed.
|
|
48
|
-
"""
|
|
49
|
-
with self._condition:
|
|
50
|
-
if self._is_closed:
|
|
51
|
-
raise QueueClosed("Can't add more values when queue is already closed.")
|
|
52
|
-
else:
|
|
53
|
-
self._deque.append(value)
|
|
54
|
-
self._condition.notify()
|
|
55
|
-
|
|
56
|
-
def get(self) -> _T:
|
|
57
|
-
"""Remove and return the value at the front of the queue.
|
|
58
|
-
|
|
59
|
-
If the queue is empty, this blocks until a new value is available.
|
|
60
|
-
If you're calling from an async task, use one of the async methods instead
|
|
61
|
-
to avoid blocking the event loop.
|
|
62
|
-
|
|
63
|
-
Raises:
|
|
64
|
-
QueueClosed: If all values have been consumed
|
|
65
|
-
and the queue has been closed with `done_putting()`.
|
|
66
|
-
"""
|
|
67
|
-
with self._condition:
|
|
68
|
-
while True:
|
|
69
|
-
if len(self._deque) > 0:
|
|
70
|
-
return self._deque.popleft()
|
|
71
|
-
elif self._is_closed:
|
|
72
|
-
raise QueueClosed("Queue closed; no more items to get.")
|
|
73
|
-
else:
|
|
74
|
-
# We don't have anything to return.
|
|
75
|
-
# Wait for something to change, then check again.
|
|
76
|
-
self._condition.wait()
|
|
77
|
-
|
|
78
|
-
def get_until_closed(self) -> Iterable[_T]:
|
|
79
|
-
"""Remove and return values from the front of the queue until it's closed.
|
|
80
|
-
|
|
81
|
-
Example:
|
|
82
|
-
for value in queue.get_until_closed():
|
|
83
|
-
print(value)
|
|
84
|
-
"""
|
|
85
|
-
while True:
|
|
86
|
-
try:
|
|
87
|
-
yield self.get()
|
|
88
|
-
except QueueClosed:
|
|
89
|
-
break
|
|
90
|
-
|
|
91
|
-
async def get_async(self) -> _T:
|
|
92
|
-
"""Like `get()`, except yield to the event loop while waiting.
|
|
93
|
-
|
|
94
|
-
Warning:
|
|
95
|
-
A waiting `get_async()` won't be interrupted by an async cancellation.
|
|
96
|
-
The proper way to interrupt a waiting `get_async()`
|
|
97
|
-
is to close the queue, just like you have to do with `get()`.
|
|
98
|
-
"""
|
|
99
|
-
return await run_sync(
|
|
100
|
-
self.get,
|
|
101
|
-
# We keep `cancellable` False so we don't leak this helper thread.
|
|
102
|
-
# If we made it True, an async cancellation here would detach us
|
|
103
|
-
# from the helper thread and allow the thread to "run to completion"--
|
|
104
|
-
# but if no more values are ever enqueued, and the queue is never closed,
|
|
105
|
-
# completion would never happen and it would hang around forever.
|
|
106
|
-
cancellable=False,
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
async def get_async_until_closed(self) -> AsyncIterable[_T]:
|
|
110
|
-
"""Like `get_until_closed()`, except yield to the event loop while waiting.
|
|
111
|
-
|
|
112
|
-
Example:
|
|
113
|
-
async for value in queue.get_async_until_closed():
|
|
114
|
-
print(value)
|
|
115
|
-
|
|
116
|
-
Warning:
|
|
117
|
-
While the ``async for`` is waiting for a new value,
|
|
118
|
-
it won't be interrupted by an async cancellation.
|
|
119
|
-
The proper way to interrupt a waiting `get_async_until_closed()`
|
|
120
|
-
is to close the queue, just like you have to do with `get()`.
|
|
121
|
-
"""
|
|
122
|
-
while True:
|
|
123
|
-
try:
|
|
124
|
-
yield await self.get_async()
|
|
125
|
-
except QueueClosed:
|
|
126
|
-
break
|
|
127
|
-
|
|
128
|
-
def done_putting(self) -> None:
|
|
129
|
-
"""Close the queue, i.e. signal that no more values will be `put()`.
|
|
130
|
-
|
|
131
|
-
You normally *must* close the queue eventually
|
|
132
|
-
to inform consumers that they can stop waiting for new values.
|
|
133
|
-
Forgetting to do this can leave them waiting forever,
|
|
134
|
-
leaking tasks or threads or causing deadlocks.
|
|
135
|
-
|
|
136
|
-
Consider using a ``with`` block instead. See `__enter__()`.
|
|
137
|
-
|
|
138
|
-
Raises:
|
|
139
|
-
QueueClosed: If the queue is already closed.
|
|
140
|
-
"""
|
|
141
|
-
with self._condition:
|
|
142
|
-
if self._is_closed:
|
|
143
|
-
raise QueueClosed("Can't close when queue is already closed.")
|
|
144
|
-
else:
|
|
145
|
-
self._is_closed = True
|
|
146
|
-
self._condition.notify_all()
|
|
147
|
-
|
|
148
|
-
def __enter__(self) -> ThreadAsyncQueue[_T]:
|
|
149
|
-
"""Use the queue as a context manager, closing the queue upon exit.
|
|
150
|
-
|
|
151
|
-
Example:
|
|
152
|
-
This:
|
|
153
|
-
|
|
154
|
-
with queue:
|
|
155
|
-
do_stuff()
|
|
156
|
-
|
|
157
|
-
Is equivalent to:
|
|
158
|
-
|
|
159
|
-
try:
|
|
160
|
-
do_stuff()
|
|
161
|
-
finally:
|
|
162
|
-
queue.done_putting()
|
|
163
|
-
"""
|
|
164
|
-
return self
|
|
165
|
-
|
|
166
|
-
def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> None:
|
|
167
|
-
"""See `__enter__()`."""
|
|
168
|
-
self.done_putting()
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
class QueueClosed(Exception):
|
|
172
|
-
"""See `ThreadAsyncQueue.done_putting()`."""
|
|
173
|
-
|
|
174
|
-
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|