Ejemplo n.º 1
0
    def __init__(self, parser, step_marker, starting_row):
        """
        Constructor:

        :param parser: The parser this container belongs to.
        :type parser: :class:`GenericSampleTransferPlanParser`

        :param step_marker: The step marker indicating this step. It
            contains a keyword an integer number.
        :class step_marker: :class:`str`

        :param starting_row: The row index of the step marker.
        :type starting_row: :class:`int`
        """
        ExcelParsingContainer.__init__(self, parser=parser)

        #: The row index of the step marker.
        self.__starting_row = starting_row
        #: Step number define the order or transfers.
        self.__number = None
        self.__parse_step_marker(step_marker)

        #: The :class:`TagDefinitionParsingContainer` containing the codes
        #: for the transfers.
        self.transfer_tag_definition = None
        if self.__number is not None:
            predicate = self._parser.TRANSFER_TAG_BASE_NAME + '%i' \
                        % (self.__number)
            self.transfer_tag_definition = TagDefinitionParsingContainer(
                        parser=self._parser, tag_predicate=predicate,
                        start_row_index=(starting_row + 1))
        #: A transfer volume applying to all transfers in this step (optional).
        self.default_volume = None
        #: The :class:`TagDefinitionParsingContainer` containing the codes
        #: for transfer volumes.
        self.volume_tag_definition = None
        #: The :class:`TagDefinitionParsingContainer` containing the codes
        #: for diluent (dilutions only) volumes.
        self.diluent_tag_definition = None

        #: The layouts for this step mapped onto roles (there can only be
        #: one layout for each role).
        self.layouts = dict()
        #: The rack containers for this step mapped onto roles.
        self.rack_containers = dict()

        #: Stores the transfer parsing containers for this step mapped onto
        #: codes.
        self.__transfer_containers = dict()
Ejemplo n.º 2
0
class _TransferStepParsingContainer(ExcelParsingContainer):
    """
    A parsing container collecting the data for one step.
    """
    _PARSER_CLS = GenericSampleTransferPlanParser

    def __init__(self, parser, step_marker, starting_row):
        """
        Constructor:

        :param parser: The parser this container belongs to.
        :type parser: :class:`GenericSampleTransferPlanParser`

        :param step_marker: The step marker indicating this step. It
            contains a keyword an integer number.
        :class step_marker: :class:`str`

        :param starting_row: The row index of the step marker.
        :type starting_row: :class:`int`
        """
        ExcelParsingContainer.__init__(self, parser=parser)

        #: The row index of the step marker.
        self.__starting_row = starting_row
        #: Step number define the order or transfers.
        self.__number = None
        self.__parse_step_marker(step_marker)

        #: The :class:`TagDefinitionParsingContainer` containing the codes
        #: for the transfers.
        self.transfer_tag_definition = None
        if self.__number is not None:
            predicate = self._parser.TRANSFER_TAG_BASE_NAME + '%i' \
                        % (self.__number)
            self.transfer_tag_definition = TagDefinitionParsingContainer(
                        parser=self._parser, tag_predicate=predicate,
                        start_row_index=(starting_row + 1))
        #: A transfer volume applying to all transfers in this step (optional).
        self.default_volume = None
        #: The :class:`TagDefinitionParsingContainer` containing the codes
        #: for transfer volumes.
        self.volume_tag_definition = None
        #: The :class:`TagDefinitionParsingContainer` containing the codes
        #: for diluent (dilutions only) volumes.
        self.diluent_tag_definition = None

        #: The layouts for this step mapped onto roles (there can only be
        #: one layout for each role).
        self.layouts = dict()
        #: The rack containers for this step mapped onto roles.
        self.rack_containers = dict()

        #: Stores the transfer parsing containers for this step mapped onto
        #: codes.
        self.__transfer_containers = dict()

    @property
    def number(self):
        """
        Step number define the order or transfers.
        """
        return self.__number

    @property
    def starting_row(self):
        """
        The row index of the step marker.
        """
        return self.__starting_row

    def get_transfer_tag_row_index(self):
        """
        Used to register the tag in the layout sheet parsing container.

        The index must be the same row index as the factor marker (that is
        one higher than the :attr:`__starting_row`) to ensure it is
        stored along with the potential volume tag definition
        """
        return (self.__starting_row + 1)

    def __parse_step_marker(self, step_marker):
        """
        The step marker must match the following pattern: "Step [integer]"
        with the integer being the step number.
        """
        tokens = step_marker.split('_')
        cell_name = self._parser.get_cell_name(self.__starting_row, 0)
        err_msg = 'Invalid step marker "%s". A valid step marker must match ' \
                  'the following pattern: "Step [integer]".' % (step_marker)
        if not len(tokens) == 2:
            self._create_error(err_msg, cell_name)
        else:
            num_str = tokens[1]
            try:
                num_str = num_str.strip()
                self.__number = int(num_str)
            except ValueError:
                self._create_error(err_msg, cell_name)

    def add_transfer_code(self, code):
        """
        Adds a transfer that will be used later to recognise source and
        target wells in the layouts.
        """
        if self.transfer_tag_definition.has_code(code):
            msg = 'Duplicate code "%s" for step %i!' % (code, self.__number)
            self._create_error(msg)
        else:
            self.transfer_tag_definition.add_code_and_value(code, code)

    def add_layout(self, role_token, layout_container, cell_name):
        """
        Parses the role of a layout and add it to the :attr:`layouts` map.

        :param role_token: The first part of the layout specifier.
        :type role_token: :class:`str`

        :param layout_container: The layout container to be added.
        :type layout_container: :class:`LayoutParsingContainer`

        :param cell_name: name of the cell of the layout specifier
            (for error messages)
        :type cell_name: :class:`str`

        :return: the role for this layout
        """
        conv_token = role_token.lower().strip()
        if conv_token == self._parser.source_role_marker:
            role = self._parser.source_role_marker
        elif conv_token == self._parser.target_role_marker:
            role = self._parser.target_role_marker
        else:
            msg = 'Unable to determine role for this layout! You have used ' \
                  '"%s". Use "%s" or "%s", please!' \
                  % (role_token, self._parser.source_role_marker,
                     self._parser.target_role_marker)
            self._create_error(msg, cell_name)
            return None

        if self.layouts.has_key(role):
            msg = 'There are several %s layouts for step %i!' % (role,
                                                                 self.__number)
            self._create_error(msg)
            return None

        self.layouts[role] = layout_container
        return role

    def get_role_for_layout(self, layout_container):
        """
        Returns the role for the passed layout or records an error.
        """
        role = None
        for layout_role, layout in self.layouts.iteritems():
            if layout == layout_container:
                role = layout_role
                break

        if role is None:
            msg = 'Programming error. Layout %s is not known for step %i!' \
                  % (layout_container, self.__number)
            self._create_error(msg)
            return None

        return role

    def add_transfer_data(self, role, code, volume, diluent, pos_container):
        """
        Fetches or creates the transfer container for this code and add the
        volume and position data to it.
        """
        if volume is None: volume = self.default_volume

        if self.__transfer_containers.has_key(code):
            transfer_container = self.__transfer_containers[code]
        else:
            transfer_container = TransferParsingContainer(parser=self._parser,
                                    code=code, diluent=diluent, volume=volume,
                                    step_number=self.__number)
            self.__transfer_containers[code] = transfer_container

        transfer_container.add_position(role, pos_container)

    def get_transfer_containers(self):
        """
        Returns the transfer containers for this step.
        """
        return self.__transfer_containers.values()

    def __eq__(self, other):
        return isinstance(other, self.__class__) and \
                self.__number == other.number

    def __str__(self):
        return '%i' % (self.__number)

    def __repr__(self):
        str_format = '<%s %i>'
        params = (self.__class__.__name__, self.__number)
        return str_format % params