<commit_before>import typing
import logging
from uuid import uuid4, UUID
from enum import Enum
from dataclasses import dataclass

from opentrons.types import Mount, Point, Location
from opentrons.hardware_control.pipette import Pipette
from opentrons.hardware_control.types import CriticalPoint, Axis

from .constants import LOOKUP_LABWARE
from .util import StateMachine, WILDCARD
from .models import ComparisonStatus
from .helper_classes import (LabwareInfo, CheckMove, Moves,
                             DeckCalibrationError, PipetteRank,
                             PipetteInfo, PipetteStatus)
from opentrons.hardware_control import ThreadManager
from opentrons.protocol_api import labware, geometry

MODULE_LOG = logging.getLogger(__name__)

"""
A set of endpoints that can be used to create a session for any robot
calibration tasks such as checking your calibration data, performing mount
offset or a robot deck transform.
"""


class CalibrationException(Exception):
    pass


class NoPipetteException(CalibrationException):
    pass


class SessionManager:
    """Small wrapper to keep track of robot calibration sessions created."""
    def __init__(self):
        self._sessions = {}

    @property
    def sessions(self):
        return self._sessions


# vector from front bottom left of slot 12
TRASH_TIP_OFFSET = Point(20, 20, -20)


class CalibrationSession:
    """Class that controls state of the current robot calibration session"""
    def __init__(self, hardware: ThreadManager):
        self._hardware = hardware
        self._deck = geometry.Deck()
        self._pip_info_by_mount = self._get_pip_info_by_mount(
                hardware.get_attached_instruments())
        self._labware_info = self._determine_required_labware()
        self._moves = self._build_deck_moves()

    @classmethod
    async def build(cls, hardware: ThreadManager):
        await hardware.cache_instruments()
        await hardware.set_lights(rails=True)
        await hardware.home()
        return cls(hardware=hardware)

    @staticmethod
    def _get_pip_info_by_mount(
            new_pipettes: typing.Dict[Mount, Pipette.DictType]) \
            -> typing.Dict[Mount, PipetteInfo]:
        pip_info_by_mount = {}
        attached_pips = {m: p for m, p in new_pipettes.items() if p}
        num_pips = len(attached_pips)
        if num_pips > 0:
            for mount, data in attached_pips.items():
                if data:
                    rank = PipetteRank.first
                    if num_pips == 2 and mount == Mount.LEFT:
                        rank = PipetteRank.second
                    cp = None
                    if data['channels'] == 8:
                        cp = CriticalPoint.FRONT_NOZZLE
                    pip_info_by_mount[mount] = PipetteInfo(tiprack_id=None,
                                                           critical_point=cp,
                                                           rank=rank,
                                                           mount=mount)
            return pip_info_by_mount
        else:
            raise NoPipetteException("Cannot start calibration check "
                                     "with fewer than one pipette.")

    def _determine_required_labware(self) -> typing.Dict[UUID, LabwareInfo]:
        """
        A function that inserts tiprack information into two dataclasses
        :py:class:`.LabwareInfo` and :py:class:`.LabwareDefinition` based
        on the current pipettes attached.
        """
        lw: typing.Dict[UUID, LabwareInfo] = {}
        _prev_lw_uuid: typing.Optional[UUID] = None

        for mount, pip_info in self._pip_info_by_mount.items():
            load_name: str = self._load_name_for_mount(mount)
            prev_lw = lw.get(_prev_lw_uuid, None) if _prev_lw_uuid else None
            if _prev_lw_uuid and prev_lw and prev_lw.loadName == load_name:
                #  pipette uses same tiprack as previous, use existing
                lw[_prev_lw_uuid].forMounts.append(mount)
                self._pip_info_by_mount[mount].tiprack_id = _prev_lw_uuid
            else:
                lw_def = labware.get_labware_definition(load_name)
                new_uuid: UUID = uuid4()
                _prev_lw_uuid = new_uuid
                slot = self._get_tip_rack_slot_for_mount(mount)
                lw[new_uuid] = LabwareInfo(
                    alternatives=self._alt_load_names_for_mount(mount),
                    forMounts=[mount],
                    loadName=load_name,
                    slot=slot,
                    namespace=lw_def['namespace'],
                    version=lw_def['version'],
                    id=new_uuid,
                    definition=lw_def)
                self._pip_info_by_mount[mount].tiprack_id = new_uuid
        return lw

    def _alt_load_names_for_mount(self, mount: Mount) -> typing.List[str]:
        pip_vol = self.pipettes[mount]['max_volume']
        return list(LOOKUP_LABWARE[str(pip_vol)].alternatives)

    def _load_name_for_mount(self, mount: Mount) -> str:
        pip_vol = self.pipettes[mount]['max_volume']
        return LOOKUP_LABWARE[str(pip_vol)].load_name

    def _build_deck_moves(self) -> Moves:
        return Moves(
                joggingFirstPipetteToHeight=self._build_height_dict('5'),
                joggingFirstPipetteToPointOne=self._build_cross_dict('1BLC'),
                joggingFirstPipetteToPointTwo=self._build_cross_dict('3BRC'),
                joggingFirstPipetteToPointThree=self._build_cross_dict('7TLC'),
                joggingSecondPipetteToHeight=self._build_height_dict('5'),
                joggingSecondPipetteToPointOne=self._build_cross_dict('1BLC'))

    def _build_cross_dict(self, pos_id: str) -> CheckMove:
        cross_coords = self._deck.get_calibration_position(pos_id).position
        return CheckMove(position=Point(*cross_coords), locationId=uuid4())

    def _build_height_dict(self, slot: str) -> CheckMove:
        pos = Point(*self._deck.get_slot_center(slot))
        updated_pos = pos - Point(20, 0, pos.z)
        return CheckMove(position=updated_pos, locationId=uuid4())

    def _get_tip_rack_slot_for_mount(self, mount) -> str:
        if len(self._pip_info_by_mount) == 2:
            shared_tiprack = self._load_name_for_mount(Mount.LEFT) == \
                    self._load_name_for_mount(Mount.RIGHT)
            if mount == Mount.LEFT and not shared_tiprack:
                return '6'
            else:
                return '8'
        else:
            return '8'<commit_msg>fix(api): calcheck: move the slot 5 check point -y (#5667)<commit_after>import typing
import logging
from uuid import uuid4, UUID
from enum import Enum
from dataclasses import dataclass

from opentrons.types import Mount, Point, Location
from opentrons.hardware_control.pipette import Pipette
from opentrons.hardware_control.types import CriticalPoint, Axis

from .constants import LOOKUP_LABWARE
from .util import StateMachine, WILDCARD
from .models import ComparisonStatus
from .helper_classes import (LabwareInfo, CheckMove, Moves,
                             DeckCalibrationError, PipetteRank,
                             PipetteInfo, PipetteStatus)
from opentrons.hardware_control import ThreadManager
from opentrons.protocol_api import labware, geometry

MODULE_LOG = logging.getLogger(__name__)

"""
A set of endpoints that can be used to create a session for any robot
calibration tasks such as checking your calibration data, performing mount
offset or a robot deck transform.
"""


class CalibrationException(Exception):
    pass


class NoPipetteException(CalibrationException):
    pass


class SessionManager:
    """Small wrapper to keep track of robot calibration sessions created."""
    def __init__(self):
        self._sessions = {}

    @property
    def sessions(self):
        return self._sessions


# vector from front bottom left of slot 12
TRASH_TIP_OFFSET = Point(20, 20, -20)


class CalibrationSession:
    """Class that controls state of the current robot calibration session"""
    def __init__(self, hardware: ThreadManager):
        self._hardware = hardware
        self._deck = geometry.Deck()
        self._pip_info_by_mount = self._get_pip_info_by_mount(
                hardware.get_attached_instruments())
        self._labware_info = self._determine_required_labware()
        self._moves = self._build_deck_moves()

    @classmethod
    async def build(cls, hardware: ThreadManager):
        await hardware.cache_instruments()
        await hardware.set_lights(rails=True)
        await hardware.home()
        return cls(hardware=hardware)

    @staticmethod
    def _get_pip_info_by_mount(
            new_pipettes: typing.Dict[Mount, Pipette.DictType]) \
            -> typing.Dict[Mount, PipetteInfo]:
        pip_info_by_mount = {}
        attached_pips = {m: p for m, p in new_pipettes.items() if p}
        num_pips = len(attached_pips)
        if num_pips > 0:
            for mount, data in attached_pips.items():
                if data:
                    rank = PipetteRank.first
                    if num_pips == 2 and mount == Mount.LEFT:
                        rank = PipetteRank.second
                    cp = None
                    if data['channels'] == 8:
                        cp = CriticalPoint.FRONT_NOZZLE
                    pip_info_by_mount[mount] = PipetteInfo(tiprack_id=None,
                                                           critical_point=cp,
                                                           rank=rank,
                                                           mount=mount)
            return pip_info_by_mount
        else:
            raise NoPipetteException("Cannot start calibration check "
                                     "with fewer than one pipette.")

    def _determine_required_labware(self) -> typing.Dict[UUID, LabwareInfo]:
        """
        A function that inserts tiprack information into two dataclasses
        :py:class:`.LabwareInfo` and :py:class:`.LabwareDefinition` based
        on the current pipettes attached.
        """
        lw: typing.Dict[UUID, LabwareInfo] = {}
        _prev_lw_uuid: typing.Optional[UUID] = None

        for mount, pip_info in self._pip_info_by_mount.items():
            load_name: str = self._load_name_for_mount(mount)
            prev_lw = lw.get(_prev_lw_uuid, None) if _prev_lw_uuid else None
            if _prev_lw_uuid and prev_lw and prev_lw.loadName == load_name:
                #  pipette uses same tiprack as previous, use existing
                lw[_prev_lw_uuid].forMounts.append(mount)
                self._pip_info_by_mount[mount].tiprack_id = _prev_lw_uuid
            else:
                lw_def = labware.get_labware_definition(load_name)
                new_uuid: UUID = uuid4()
                _prev_lw_uuid = new_uuid
                slot = self._get_tip_rack_slot_for_mount(mount)
                lw[new_uuid] = LabwareInfo(
                    alternatives=self._alt_load_names_for_mount(mount),
                    forMounts=[mount],
                    loadName=load_name,
                    slot=slot,
                    namespace=lw_def['namespace'],
                    version=lw_def['version'],
                    id=new_uuid,
                    definition=lw_def)
                self._pip_info_by_mount[mount].tiprack_id = new_uuid
        return lw

    def _alt_load_names_for_mount(self, mount: Mount) -> typing.List[str]:
        pip_vol = self.pipettes[mount]['max_volume']
        return list(LOOKUP_LABWARE[str(pip_vol)].alternatives)

    def _load_name_for_mount(self, mount: Mount) -> str:
        pip_vol = self.pipettes[mount]['max_volume']
        return LOOKUP_LABWARE[str(pip_vol)].load_name

    def _build_deck_moves(self) -> Moves:
        return Moves(
                joggingFirstPipetteToHeight=self._build_height_dict('5'),
                joggingFirstPipetteToPointOne=self._build_cross_dict('1BLC'),
                joggingFirstPipetteToPointTwo=self._build_cross_dict('3BRC'),
                joggingFirstPipetteToPointThree=self._build_cross_dict('7TLC'),
                joggingSecondPipetteToHeight=self._build_height_dict('5'),
                joggingSecondPipetteToPointOne=self._build_cross_dict('1BLC'))

    def _build_cross_dict(self, pos_id: str) -> CheckMove:
        cross_coords = self._deck.get_calibration_position(pos_id).position
        return CheckMove(position=Point(*cross_coords), locationId=uuid4())

    def _build_height_dict(self, slot: str) -> CheckMove:
        pos = self._deck.get_slot_center(slot)
        ydim: float\
            = self._deck.get_slot_definition(slot)['boundingBox']['yDimension']
        # shift down to 10mm +y of the slot edge to both stay clear of the
        # slot boundary, avoid the engraved slot number, and avoid the
        # tiprack colliding if this is a multi
        updated_pos = pos - Point(0, (ydim/2)-10, pos.z)
        return CheckMove(position=updated_pos, locationId=uuid4())

    def _get_tip_rack_slot_for_mount(self, mount) -> str:
        if len(self._pip_info_by_mount) == 2:
            shared_tiprack = self._load_name_for_mount(Mount.LEFT) == \
                    self._load_name_for_mount(Mount.RIGHT)
            if mount == Mount.LEFT and not shared_tiprack:
                return '6'
            else:
                return '8'
        else:
            return '8'
{'fraction_non_alphanumeric': 0.07898658718330849, 'fraction_numerical': 0.004769001490312966, 'mean_word_length': 2.245707376058041, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6886036', 'n_tokens_mistral': 3968, 'n_tokens_neox': 3792, 'n_words': 853}