예제 #1
0
    def update_sample(self,
                      lims_id: str,
                      sex=None,
                      target_reads: int = None,
                      name: str = None,
                      **kwargs):
        """Update information about a sample."""
        lims_sample = Sample(self, id=lims_id)

        if sex:
            lims_gender = REV_SEX_MAP.get(sex)
            if lims_gender:
                lims_sample.udf[PROP2UDF["sex"]] = lims_gender
        if name:
            lims_sample.name = name
        if isinstance(target_reads, int):
            lims_sample.udf[PROP2UDF["target_reads"]] = target_reads

        for key, value in kwargs.items():
            if not PROP2UDF.get(key):
                raise LimsDataError(
                    f"Unknown how to set {key} in LIMS since it is not defined in {PROP2UDF}"
                )
            lims_sample.udf[PROP2UDF[key]] = value

        lims_sample.put()
예제 #2
0
    def capture_kit(self, lims_id: str) -> str:
        """Get capture kit for a LIMS sample."""

        step_names_udfs = MASTER_STEPS_UDFS["capture_kit_step"]
        capture_kits = set()

        lims_sample = Sample(self, id=lims_id)
        capture_kit = lims_sample.udf.get("Bait Set")

        if capture_kit and capture_kit != "NA":
            return capture_kit

        for process_type in step_names_udfs:
            artifacts = self.get_artifacts(samplelimsid=lims_id,
                                           process_type=process_type,
                                           type="Analyte")
            udf_key = step_names_udfs[process_type]
            capture_kits = capture_kits.union(
                self._find_capture_kits(artifacts, udf_key)
                or self._find_twist_capture_kits(artifacts, udf_key))

        if len(capture_kits) > 1:
            message = f"Capture kit error: {lims_sample.id} | {capture_kits}"
            raise LimsDataError(message)

        if len(capture_kits) == 1:
            return capture_kits.pop()

        return None
예제 #3
0
    def get_received_date(self, lims_id: str) -> dt.date:
        """Get the date when a sample was received."""

        sample = Sample(self, id=lims_id)
        try:
            date = sample.udf.get("Received at")
        except HTTPError:
            date = None
        return date
예제 #4
0
    def get_delivery_date(self, lims_id: str) -> dt.date:
        """Get delivery date for a sample."""

        sample = Sample(self, id=lims_id)
        try:
            date = sample.udf.get("Delivered at")
        except HTTPError:
            date = None
        return date
예제 #5
0
    def get_sequenced_date(self, lims_id: str) -> dt.date:
        """Get the date when a sample was sequenced."""

        sample = Sample(self, id=lims_id)
        try:
            date = sample.udf.get("Sequencing Finished")
        except HTTPError:
            date = None
        return date
예제 #6
0
    def get_sample_attribute(self, lims_id: str, key: str) -> str:
        """Get data from a sample."""

        sample = Sample(self, id=lims_id)
        if not PROP2UDF.get(key):
            raise LimsDataError(
                f"Unknown how to get {key} from LIMS since it is not defined in "
                f"{PROP2UDF}")
        return sample.udf[PROP2UDF[key]]
예제 #7
0
    def get_prepared_date(self, lims_id: str) -> dt.date:
        """Get the date when a sample was prepared in the lab."""

        sample = Sample(self, id=lims_id)
        try:
            date = sample.udf.get("Library Prep Finished")
        except HTTPError:
            date = None
        return date
예제 #8
0
def test_A(server_test1):
    # GIVEN: A lims with a sample with the udf 'customer': 'cust002'

    # WHEN creating a genologics Sample entity of that sample
    lims = Lims("http://127.0.0.1:8000", 'dummy', 'dummy')
    s = Sample(lims, id='ACC2351A1')

    # THEN the sample instance should have the udf
    assert s.udf['customer'] == 'cust002'
예제 #9
0
def test_D(server_test1):
    # GIVEN: A lims with a sample with:
    #   name: 'maya'
    #   Udf "Source": "blood", "Reads missing (M)": 0

    # WHEN creating a genologics Lims object and filtering on the fields.
    lims = Lims("http://127.0.0.1:8000", 'dummy', 'dummy')
    samples = lims.get_samples(udf={"Source": "blood", "Reads missing (M)": 0}, name='maya')

    # Then the sample should be found
    assert samples == [Sample(lims, id='ACC2351A2')]
예제 #10
0
파일: order.py 프로젝트: eriksjolund/cg
 def save_samples(self,
                  sample_details: ObjectifiedElement,
                  map_samples=False):
     """Save a batch of samples."""
     sample_uri = f"{self.get_uri()}/samples/batch/create"
     results = self.save_xml(sample_uri, sample_details)
     if map_samples:
         sample_map = {}
         for link in results.findall("link"):
             lims_sample = Sample(self, uri=link.attrib["uri"])
             sample_map[lims_sample.name] = lims_sample
         return sample_map
     return results
예제 #11
0
 def update_sample(self,
                   lims_id: str,
                   sex=None,
                   application: str = None,
                   target_reads: int = None):
     """Update information about a sample."""
     lims_sample = Sample(self, id=lims_id)
     if sex:
         lims_gender = REV_SEX_MAP.get(sex)
         if lims_gender:
             lims_sample.udf[PROP2UDF['sex']] = lims_gender
     if application:
         lims_sample.udf[PROP2UDF['application']] = application
     if isinstance(target_reads, int):
         lims_sample.udf[PROP2UDF['target_reads']] = target_reads
     lims_sample.put()
예제 #12
0
    def sample(self, lims_id, is_cgid=False):
        """Get a unique sample from LIMS."""
        if is_cgid:
            udf_key = 'Clinical Genomics ID'
            lims_samples = self.get_samples(udf={udf_key: lims_id})
            if len(lims_samples) == 1:
                return lims_samples[0]
            elif len(lims_samples) > 1:
                matches_str = ', '.join(sample.id for sample in lims_samples)
                message = "'{}' matches: {}".format(lims_id, matches_str)
                raise MultipleSamplesError(message)
            else:
                # no matching samples
                return None
        else:
            lims_sample = Sample(self, id=lims_id)

        return lims_sample
예제 #13
0
def submit_dx_samples():
    form = SubmitDXSampleForm()

    if form.validate_on_submit():
        container_type = Containertype(lims, id='2')  # Tube
        workflow = Workflow(lims, id=app.config['LIMS_DX_SAMPLE_SUBMIT_WORKFLOW'])

        for sample_name in form.parsed_samples:
            # Get or create project
            lims_projects = lims.get_projects(name=form.parsed_samples[sample_name]['project'])
            if not lims_projects:
                lims_project = Project.create(lims, name=form.parsed_samples[sample_name]['project'], researcher=form.researcher, udf={'Application': 'DX'})
            else:
                lims_project = lims_projects[0]

            # Set sample udf data
            udf_data = form.parsed_worklist[sample_name]
            udf_data['Sample Type'] = form.parsed_samples[sample_name]['type']
            udf_data['Dx Fragmentlengte (bp) Externe meting'] = form.pool_fragment_length.data
            udf_data['Dx Conc. (ng/ul) Externe meting'] = form.pool_concentration.data
            udf_data['Dx Exoomequivalent'] = form.parsed_samples[sample_name]['exome_count']

            # Create sample
            container = Container.create(lims, type=container_type, name=udf_data['Dx Fractienummer'])
            sample = Sample.create(lims, container=container, position='1:1', project=lims_project, name=sample_name, udf=udf_data)
            print sample.name, sample.artifact.name

            # Add reagent label (barcode)
            artifact = sample.artifact
            artifact_xml_dom = minidom.parseString(artifact.xml())

            for artifact_name_node in artifact_xml_dom.getElementsByTagName('name'):
                parent = artifact_name_node.parentNode
                reagent_label = artifact_xml_dom.createElement('reagent-label')
                reagent_label.setAttribute('name', form.parsed_samples[sample_name]['barcode'])
                parent.appendChild(reagent_label)
                lims.put(artifact.uri, artifact_xml_dom.toxml(encoding='utf-8'))

            lims.route_artifacts([sample.artifact], workflow_uri=workflow.uri)

        return render_template('submit_dx_samples_done.html', title='Submit DX samples', project_name=lims_project.name, form=form)
    return render_template('submit_dx_samples.html', title='Submit DX samples', form=form)
예제 #14
0
 def capture_kit(self, lims_id: str) -> str:
     """Get capture kit for a LIMS sample."""
     lims_sample = Sample(self, id=lims_id)
     capture_kit = lims_sample.udf.get('Capture Library version')
     if capture_kit and capture_kit != 'NA':
         return capture_kit
     else:
         artifacts = self.get_artifacts(
             samplelimsid=lims_id,
             process_type='CG002 - Hybridize Library  (SS XT)',
             type='Analyte')
         udf_key = 'SureSelect capture library/libraries used'
         capture_kits = set(
             artifact.parent_process.udf.get(udf_key)
             for artifact in artifacts)
         if len(capture_kits) == 1:
             return capture_kits.pop()
         else:
             message = f"Capture kit error: {lims_sample.id} | {capture_kits}"
             raise LimsDataError(message)
예제 #15
0
 def test_create_entity(self):
     with patch('genologics.lims.requests.post',
                return_value=Mock(content=self.sample_creation, status_code=201)) as patch_post:
         l = Sample.create(
             self.lims,
             project=Project(self.lims, uri='project'),
             container=Container(self.lims, uri='container'),
             position='1:1',
             name='s1',
         )
         data = '''<?xml version=\'1.0\' encoding=\'utf-8\'?>
         <smp:samplecreation xmlns:smp="http://genologics.com/ri/sample">
         <name>s1</name>
         <project uri="project" limsid="project" />
         <location>
           <container uri="container" />
           <value>1:1</value>
         </location>
         </smp:samplecreation>'''
         assert elements_equal(ElementTree.fromstring(patch_post.call_args_list[0][1]['data']),
                               ElementTree.fromstring(data))
예제 #16
0
 def test_create_entity(self):
     with patch('genologics.lims.requests.post',
                return_value=Mock(content=self.sample_creation, status_code=201)) as patch_post:
         l = Sample.create(
             self.lims,
             project=Project(self.lims, uri='project'),
             container=Container(self.lims, uri='container'),
             position='1:1',
             name='s1',
         )
         data = '''<?xml version=\'1.0\' encoding=\'utf-8\'?>
         <smp:samplecreation xmlns:smp="http://genologics.com/ri/sample">
         <name>s1</name>
         <project uri="project" />
         <location>
           <container uri="container" />
           <value>1:1</value>
         </location>
         </smp:samplecreation>'''
         assert elements_equal(ElementTree.fromstring(patch_post.call_args_list[0][1]['data']),
                               ElementTree.fromstring(data))
예제 #17
0
 def sample(self, lims_id: str):
     """Fetch a sample from the LIMS database."""
     lims_sample = Sample(self, id=lims_id)
     return self._export_sample(lims_sample)
예제 #18
0
def from_helix(lims, email_settings, input_file):
    """Upload samples from helix export file."""
    project_name = 'Dx {filename}'.format(filename=input_file.name.rstrip('.csv').split('/')[-1])
    helix_initials = project_name.split('_')[-1]

    # Try lims connection
    try:
        lims.check_version()
    except ConnectionError:
        subject = "ERROR Lims Helix Upload: {0}".format(project_name)
        message = "Can't connect to lims server, please contact a lims administrator."
        send_email(email_settings['server'], email_settings['from'], email_settings['to_import_helix'], subject, message)
        sys.exit(message)

    # Get researcher using helix initials
    for researcher in lims.get_researchers():
        if researcher.fax == helix_initials:  # Use FAX as intials field as the lims initials field can't be edited via the 5.0 web interface.
            email_settings['to_import_helix'].append(researcher.email)
            break
    else:   # No researcher found
        subject = "ERROR Lims Helix Upload: {0}".format(project_name)
        message = "Can't find researcher with initials: {0}.".format(helix_initials)
        send_email(email_settings['server'], email_settings['from'], email_settings['to_import_helix'], subject, message)
        sys.exit(message)

    # Create project
    if not lims.get_projects(name=project_name):
        project = Project.create(lims, name=project_name, researcher=researcher, udf={'Application': 'DX'})
    else:
        subject = "ERROR Lims Helix Upload: {0}".format(project_name)
        message = "Duplicate project / werklijst. Samples not loaded."
        send_email(email_settings['server'], email_settings['from'], email_settings['to_import_helix'], subject, message)
        sys.exit(message)

    container_type = Containertype(lims, id='2')  # Tube

    # match header and udf fields
    udf_column = {
        'Dx Onderzoeknummer': {'column': 'Onderzoeknummer'},
        'Dx Fractienummer': {'column': 'Fractienummer'},
        'Dx Monsternummer': {'column': 'Monsternummer'},
        'Dx Concentratie (ng/ul)': {'column': 'Concentratie (ng/ul)'},
        'Dx Materiaal type': {'column': 'Materiaal'},
        'Dx Foetus': {'column': 'Foetus'},
        'Dx Foetus ID': {'column': 'Foet_id'},
        'Dx Foetus geslacht': {'column': 'Foetus_geslacht'},
        'Dx Overleden': {'column': 'Overleden'},
        'Dx Opslaglocatie': {'column': 'Opslagpositie'},
        'Dx Spoed': {'column': 'Spoed'},
        'Dx NICU Spoed': {'column': 'NICU Spoed'},
        'Dx Persoons ID': {'column': 'Persoons_id'},
        'Dx Werklijstnummer': {'column': 'Werklijstnummer'},
        'Dx Familienummer': {'column': 'Familienummer'},
        'Dx Geslacht': {'column': 'Geslacht'},
        'Dx Geboortejaar': {'column': 'Geboortejaar'},
        'Dx Meet ID': {'column': 'Stof_meet_id'},
        'Dx Stoftest code': {'column': 'Stoftestcode'},
        'Dx Stoftest omschrijving': {'column': 'Stoftestomschrijving'},
        'Dx Onderzoeksindicatie': {'column': 'Onderzoeksindicatie'},
        'Dx Onderzoeksreden': {'column': 'Onderzoeksreden'},
        'Dx Protocolcode': {'column': 'Protocolcode'},
        'Dx Protocolomschrijving': {'column': 'Protocolomschrijving'},
        'Dx Einddatum': {'column': 'Einddatum'},
        'Dx Gerelateerde onderzoeken': {'column': 'Gerelateerde onderzoeken'},
    }
    header = input_file.readline().rstrip().split(',')  # expect header on first line
    for udf in udf_column:
        udf_column[udf]['index'] = header.index(udf_column[udf]['column'])

    # Setup email
    subject = "Lims Helix Upload: {0}".format(project_name)
    message = "Project: {0}\n\nSamples:\n".format(project_name)

    # Parse samples
    for line in input_file:
        data = line.rstrip().strip('"').split('","')

        udf_data = {'Sample Type': 'DNA isolated', 'Dx Import warning': ''}  # required lims input
        for udf in udf_column:
            # Transform specific udf
            if udf in ['Dx Overleden', 'Dx Spoed', 'Dx NICU Spoed']:
                udf_data[udf] = clarity_epp.upload.utils.char_to_bool(data[udf_column[udf]['index']])
            elif udf in ['Dx Geslacht', 'Dx Foetus geslacht']:
                udf_data[udf] = clarity_epp.upload.utils.transform_sex(data[udf_column[udf]['index']])
            elif udf == 'Dx Foetus':
                udf_data[udf] = bool(data[udf_column[udf]['index']].strip())
            elif udf == 'Dx Concentratie (ng/ul)':
                udf_data[udf] = data[udf_column[udf]['index']].replace(',', '.')
            elif udf in ['Dx Monsternummer', 'Dx Fractienummer']:
                udf_data[udf] = clarity_epp.upload.utils.transform_sample_name(data[udf_column[udf]['index']])
            elif udf == 'Dx Gerelateerde onderzoeken':
                udf_data[udf] = data[udf_column[udf]['index']].replace(',', ';')
            elif udf == 'Dx Einddatum':
                date = datetime.strptime(data[udf_column[udf]['index']], '%d-%m-%Y')  # Helix format (14-01-2021)
                udf_data[udf] = date.strftime('%Y-%m-%d')  # LIMS format (2021-01-14)
            else:
                udf_data[udf] = data[udf_column[udf]['index']]

        sample_name = udf_data['Dx Monsternummer']

        # Set 'Dx Handmatig' udf
        if udf_data['Dx Foetus'] or udf_data['Dx Overleden'] or udf_data['Dx Materiaal type'] not in ['BL', 'BLHEP', 'BM', 'BMEDTA']:
            udf_data['Dx Handmatig'] = True
        else:
            udf_data['Dx Handmatig'] = False

        # Set 'Dx Familie status' udf
        if udf_data['Dx Onderzoeksreden'] == 'Bevestiging diagnose':
            udf_data['Dx Familie status'] = 'Kind'
        elif udf_data['Dx Onderzoeksreden'] == 'Prenataal onderzoek':
            udf_data['Dx Familie status'] = 'Kind'
        elif udf_data['Dx Onderzoeksreden'] == 'Eerstegraads-verwantenond':
            udf_data['Dx Familie status'] = 'Kind'
        elif udf_data['Dx Onderzoeksreden'] == 'Partneronderzoek':
            udf_data['Dx Familie status'] = 'Kind'
        elif udf_data['Dx Onderzoeksreden'] == 'Informativiteitstest':
            udf_data['Dx Familie status'] = 'Ouder'
        else:
            udf_data['Dx Import warning'] = ';'.join(['Onbekende onderzoeksreden, familie status niet ingevuld.', udf_data['Dx Import warning']])

        # Set 'Dx Geslacht' and 'Dx Geboortejaar' with 'Foetus' information if 'Dx Foetus == True'
        if udf_data['Dx Foetus']:
            udf_data['Dx Geslacht'] = udf_data['Dx Foetus geslacht']
            udf_data['Dx Geboortejaar'] = ''

        # Set 'Dx Geslacht = Onbekend' if 'Dx Onderzoeksindicatie == DSD00'
        if udf_data['Dx Onderzoeksindicatie'] == 'DSD00' and udf_data['Dx Familie status'] == 'Kind':
            udf_data['Dx Geslacht'] = 'Onbekend'

        # Check 'Dx Familienummer' and correct
        if '/' in udf_data['Dx Familienummer']:
            udf_data['Dx Import warning'] = ';'.join([
                'Meerdere familienummers, laatste wordt gebruikt. ({0})'.format(udf_data['Dx Familienummer']),
                udf_data['Dx Import warning']
            ])
            udf_data['Dx Familienummer'] = udf_data['Dx Familienummer'].split('/')[-1].strip(' ')

        sample_list = lims.get_samples(name=sample_name)

        if sample_list:
            sample = sample_list[0]
            if udf_data['Dx Protocolomschrijving'] in sample.udf['Dx Protocolomschrijving']:
                message += "{0}\tERROR: Duplicate sample and Protocolomschrijving code: {1}.\n".format(sample_name, udf_data['Dx Protocolomschrijving'])
            else:
                # Update existing sample if new Protocolomschrijving and thus workflow.

                # Append udf fields
                append_udf = [
                    'Dx Onderzoeknummer', 'Dx Onderzoeksindicatie', 'Dx Onderzoeksreden', 'Dx Werklijstnummer', 'Dx Protocolcode', 'Dx Protocolomschrijving',
                    'Dx Meet ID', 'Dx Stoftest code', 'Dx Stoftest omschrijving'
                ]
                for udf in append_udf:
                    sample.udf[udf] = ';'.join([udf_data[udf], str(sample.udf[udf])])

                # Update udf fields
                update_udf = ['Dx Overleden', 'Dx Spoed', 'Dx NICU Spoed', 'Dx Handmatig', 'Dx Opslaglocatie', 'Dx Import warning']
                for udf in update_udf:
                    sample.udf[udf] = udf_data[udf]

                # Add to new workflow
                workflow = clarity_epp.upload.utils.stoftestcode_to_workflow(lims, udf_data['Dx Stoftest code'])
                if workflow:
                    sample.put()
                    lims.route_artifacts([sample.artifact], workflow_uri=workflow.uri)
                    message += "{0}\tUpdated and added to workflow: {1}.\n".format(sample.name, workflow.name)
                else:
                    message += "{0}\tERROR: Stoftest code {1} is not linked to a workflow.\n".format(sample.name, udf_data['Dx Stoftest code'])

        else:
            # Check other samples from patient
            sample_list = lims.get_samples(udf={'Dx Persoons ID': udf_data['Dx Persoons ID']})
            for sample in sample_list:
                if sample.udf['Dx Protocolomschrijving'] == udf_data['Dx Protocolomschrijving'] and sample.udf['Dx Foetus'] == udf_data['Dx Foetus']:
                    udf_data['Dx Import warning'] = ';'.join(['Onderzoek reeds uitgevoerd.', udf_data['Dx Import warning']])

            # Add sample to workflow
            workflow = clarity_epp.upload.utils.stoftestcode_to_workflow(lims, udf_data['Dx Stoftest code'])
            if workflow:
                container = Container.create(lims, type=container_type, name=udf_data['Dx Fractienummer'])
                sample = Sample.create(lims, container=container, position='1:1', project=project, name=sample_name, udf=udf_data)
                lims.route_artifacts([sample.artifact], workflow_uri=workflow.uri)
                message += "{0}\tCreated and added to workflow: {1}.\n".format(sample.name, workflow.name)
            else:
                message += "{0}\tERROR: Stoftest code {1} is not linked to a workflow.\n".format(sample_name, udf_data['Dx Stoftest code'])

    # Send final email
    send_email(email_settings['server'], email_settings['from'], email_settings['to_import_helix'], subject, message)
예제 #19
0
def submit_samples():
    form = SubmitSampleForm()

    if form.validate_on_submit():
        # Create lims project
        lims_project = Project.create(
            lims,
            name=app.config['LIMS_INDICATIONS'][form.indicationcode.data]['project_name_prefix'],
            researcher=form.researcher,
            udf={'Application': form.indicationcode.data}
        )
        lims_project.name = '{0}_{1}'.format(lims_project.name, lims_project.id)
        lims_project.put()

        # Save attachment
        attachment = form.attachment.data
        if attachment:
            temp_dir = mkdtemp()
            attachment_path = path.join(temp_dir, secure_filename(attachment.filename))
            attachment.save(attachment_path)
            print attachment_path
            lims.upload_new_file(lims_project, attachment_path)
            rmtree(temp_dir)

        # Create Samples
        lims_container_type = Containertype(lims, id='2')  # Tube
        sample_artifacts = []
        for sample in form.parsed_samples:
            lims_container = Container.create(lims, type=lims_container_type, name=sample['name'])
            sample_udf_data = {
                'Sample Type': 'DNA library',
                'Dx Fragmentlengte (bp) Externe meting': form.pool_fragment_length.data,
                'Dx Conc. (ng/ul) Externe meting': form.pool_concentration.data,
                'Dx Exoomequivalent': sample['exome_count'],
            }
            lims_sample = Sample.create(lims, container=lims_container, position='1:1', project=lims_project, name=sample['name'], udf=sample_udf_data)
            print lims_sample.name, lims_sample.artifact.name
            artifact = lims_sample.artifact
            sample_artifacts.append(artifact)

            # Add reagent label (barcode)
            artifact_xml_dom = minidom.parseString(artifact.xml())
            for artifact_name_node in artifact_xml_dom.getElementsByTagName('name'):
                parent = artifact_name_node.parentNode
                reagent_label = artifact_xml_dom.createElement('reagent-label')
                reagent_label.setAttribute('name', sample['barcode'])
                parent.appendChild(reagent_label)
                lims.put(artifact.uri, artifact_xml_dom.toxml(encoding='utf-8'))

        # Route artifacts to workflow
        workflow = Workflow(lims, id=app.config['LIMS_INDICATIONS'][form.indicationcode.data]['workflow_id'])
        lims.route_artifacts(sample_artifacts, workflow_uri=workflow.uri)

        # Send email
        subject = "Clarity Portal Sample Upload - {0}".format(lims_project.name)
        message = "Gebruikersnaam\t{0}\n".format(form.username.data)
        message += "Indicatie code\t{0}\n".format(form.indicationcode.data)
        message += "Lims Project naam\t{0}\n".format(lims_project.name)
        message += "Pool - Fragment lengte\t{0}\n".format(form.pool_fragment_length.data)
        message += "Pool - Concentratie\t{0}\n".format(form.pool_concentration.data)
        message += "Pool - Exoom equivalenten\t{0}\n\n".format(form.sum_exome_count)
        message += "Sample naam\tBarcode\tExome equivalenten\tSample type\n"

        for sample in form.parsed_samples:
            message += "{0}\t{1}\t{2}\t{3}\n".format(sample['name'], sample['barcode'], sample['exome_count'], sample['type'])
        send_email(app.config['EMAIL_FROM'], app.config['LIMS_INDICATIONS'][form.indicationcode.data]['email_to'], subject, message)

        return render_template('submit_samples_done.html', title='Submit samples', project_name=lims_project.name, form=form)
    return render_template('submit_samples.html', title='Submit samples', form=form)