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()
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