Find .fastq files for each sample and move them to an appropriately named folder
3635
def movefastq(self):
        """"""
        logging.info('Moving FASTQ files')
        # Iterate through each sample
        for sample in self.metadata.runmetadata.samples:
            # Retrieve the output directory
            outputdir = os.path.join(self.path, sample.name)
            # Find any fastq files with the sample name
            fastqfiles = sorted(glob(os.path.join(self.path, '{}_*.fastq*'.format(sample.name)))) \
                if sorted(glob(os.path.join(self.path, '{}_*.fastq*'.format(sample.name)))) \
                else sorted(glob(os.path.join(self.path, '{}.fastq*'.format(sample.name)))) \
                if sorted(glob(os.path.join(self.path, '{}.fastq*'.format(sample.name)))) \
                else sorted(glob(os.path.join(self.path, '{}*.fastq*'.format(sample.name))))
            # Only try and move the files if the files exist
            if fastqfiles:
                make_path(outputdir)
                # Symlink the fastq files to the directory
                try:
                    list(map(lambda x: os.symlink(os.path.join('..', os.path.basename(x)),
                                                  os.path.join(outputdir, os.path.basename(x))), fastqfiles))
                except OSError:
                    pass
                # Find any fastq files with the sample name
                fastqfiles = [fastq for fastq in sorted(glob(os.path.join(outputdir, '{}*.fastq*'.format(sample.name))))
                              if 'trimmed' not in fastq and 'normalised' not in fastq and 'corrected' not in fastq
                              and 'paired' not in fastq and 'unpaired' not in fastq]
            else:
                if outputdir:
                    # Find any fastq files with the sample name
                    fastqfiles = [fastq for fastq in sorted(glob(os.path.join(
                        outputdir, '{}*.fastq*'.format(outputdir, sample.name))))
                                  if 'trimmed' not in fastq and 'normalised' not in fastq and 'corrected' not in fastq
                                  and 'paired' not in fastq and 'unpaired' not in fastq]
            sample.general.fastqfiles = fastqfiles
532517
def filer(args):
        
        # List to store all the metadata objects
        samples = list()
        # Find all the sequence files in the path
        fastas = sorted(glob(os.path.join(args.sequencepath, '*.fa*')))
        for fasta in fastas:
            # Create a metadata object for each sample
            metadata = MetadataObject()
            # Populate the metadata object with the required attributes
            metadata.name = os.path.splitext(os.path.basename(fasta))[0]
            metadata.general = GenObject()
            metadata.commands = GenObject()
            metadata.general.bestassemblyfile = fasta
            metadata.general.outputdirectory = os.path.join(args.sequencepath, metadata.name)
            samples.append(metadata)
        return samples
164656
def fastqfilter(self):
        """"""
        printtime('Creating filtered .fastqfiles', self.start)
        # Create and start threads
        for i in range(self.cpus):
            # Send the threads to the appropriate destination function
            threads = Thread(target=self.filterfastq, args=())
            # Set the daemon to true - something to do with thread management
            threads.setDaemon(True)
            # Start the threading
            threads.start()
        for sample in self.runmetadata.samples:
            self.filterqueue.put(sample)
        self.filterqueue.join()
        # Print the metadata to file
        metadataprinter.MetadataPrinter(self)
246525
def write_fasta(file_path, seq_list, name_list=None):
    
    if name_list is None:
        name_list = [str(i) for i in range(len(seq_list))]

    # needs to be dict or seq
    with open(file_path, "w") as f:
        for i in range(len(seq_list)):
            f.write(">" + name_list[i] + "\n" + seq_list[i] + "\n")
307631
def validate_fastq(self):
        
        logging.info('Validating FASTQ files')
        with progressbar(self.metadata) as bar:
            for sample in bar:
                # Tiny files can pass the validation tests - ensure that they don't
                size = os.path.getsize(sample.general.fastqfiles[0])
                if size >= 1000000:
                    # Try to run reformat.sh on the reads - on any errors try to run repair.sh
                    try:
                        out, err, cmd = bbtools.validate_reads(forward_in=sample.general.fastqfiles[0],
                                                               returncmd=True)
                        write_to_logfile(out, err, self.logfile, sample.general.logout, sample.general.logerr,
                                         None, None)
                    except CalledProcessError:
                        # Set the file names for the reformatted and repaired files
                        outputfile1 = os.path.join(sample.general.outputdirectory, '{}_reformatted_R1.fastq.gz'
                                                   .format(sample.name))
                        repair_file1 = os.path.join(sample.general.outputdirectory, '{}_repaired_R1.fastq.gz'
                                                    .format(sample.name))
                        if len(sample.general.fastqfiles) == 2:
                            outputfile2 = os.path.join(sample.general.outputdirectory, '{}_reformatted_R2.fastq.gz'
                                                       .format(sample.name))
                            repair_file2 = os.path.join(sample.general.outputdirectory, '{}_repaired_R2.fastq.gz'
                                                        .format(sample.name))
                        else:
                            outputfile2 = str()
                            repair_file2 = str()
                        # Use reformat.sh to repair the reads. If this fails, discard the sample from the analyses
                        try:
                            logging.warning('Errors detected in FASTQ files for sample {sample}. '
                                            'Please check the following files for details {log} {logout} {logerr}. '
                                            'The pipeline will use reformat.sh to attempt to repair issues'
                                            .format(sample=sample.name,
                                                    log=self.logfile,
                                                    logout=sample.general.logout,
                                                    logerr=sample.general.logerr))
                            if not os.path.isfile(outputfile1):
                                # Run reformat.sh
                                out, err, cmd = bbtools.reformat_reads(forward_in=sample.general.fastqfiles[0],
                                                                       forward_out=outputfile1,
                                                                       returncmd=True)
                                write_to_logfile(out, err, self.logfile, sample.general.logout, sample.general.logerr,
                                                 None, None)
                                # Run repair.sh (if necessary)
                                if outputfile2:
                                    out, err, cmd = bbtools.repair_reads(forward_in=outputfile1,
                                                                         forward_out=repair_file1,
                                                                         returncmd=True)
                                    write_to_logfile(out, err, self.logfile, sample.general.logout,
                                                     sample.general.logerr, None, None)
                            # Ensure that the output file(s) exist before declaring this a success
                            if os.path.isfile(outputfile1):
                                # Update the fastqfiles attribute to point to the repaired files
                                sample.general.fastqfiles = [repair_file1, repair_file2] if repair_file2 \
                                    else [outputfile1]
                        except CalledProcessError:
                            # The file(s) can be created even if there is STDERR from reformat.sh
                            if os.path.isfile(outputfile1) and outputfile2:
                                try:
                                    out, err, cmd = bbtools.repair_reads(forward_in=outputfile1,
                                                                         forward_out=repair_file1,
                                                                         returncmd=True)
                                    write_to_logfile(out, err, self.logfile, sample.general.logout,
                                                     sample.general.logerr, None, None)
                                    # Update the fastqfiles attribute to point to the repaired files
                                    sample.general.fastqfiles = [repair_file1, repair_file2] if repair_file2 else \
                                        [repair_file1]
                                except CalledProcessError:
                                    # Write in the logs that there was an error detected in the FASTQ files
                                    write_to_logfile('An error was detected in the FASTQ files for sample {}. '
                                                     'These files will not be processed further'.format(sample.name),
                                                     'An error was detected in the FASTQ files for sample {}. '
                                                     'These files will not be processed further'.format(sample.name),
                                                     self.logfile,
                                                     sample.general.logout,
                                                     sample.general.logerr,
                                                     None,
                                                     None)
                                    # Update metadata objects with error
                                    self.error(sample, 'fastq_error')
                            else:
                                # Write in the logs that there was an error detected in the FASTQ files
                                write_to_logfile('An error was detected in the FASTQ files for sample {}. '
                                                 'These files will not be processed further'.format(sample.name),
                                                 'An error was detected in the FASTQ files for sample {}. '
                                                 'These files will not be processed further'.format(sample.name),
                                                 self.logfile,
                                                 sample.general.logout,
                                                 sample.general.logerr,
                                                 None,
                                                 None)

                                # Update metadata objects with error
                                self.error(sample, 'fastq_error')
                else:
                    # Update metadata objects with error
                    self.error(sample, 'files_too_small')
        # Print the metadata to file
        metadataprinter.MetadataPrinter(self)
442462
def get_cf_files(path, queue):
    """"""
    for root, _, files in os.walk(os.path.abspath(path)):
        if not files:
            continue
        for filename in files:
            fullname = os.path.join(root, filename)
            if os.path.isfile(fullname) and fullname.endswith('.cf') or \
                    fullname.endswith('.post'):
                queue.put(fullname)
1303438
def fasta(self):
        
        logging.info('Converting FASTQ files to FASTA format')
        # Create the threads for the analysis
        for _ in range(self.cpus):
            threads = Thread(target=self.fastathreads, args=())
            threads.setDaemon(True)
            threads.start()
        with progressbar(self.runmetadata.samples) as bar:
            for sample in bar:
                if sample.general.bestassemblyfile != 'NA':
                    # Set the name as the FASTA file - the same as the FASTQ, but with .fa file extension
                    sample[self.analysistype].fasta = \
                        os.path.splitext(sample[self.analysistype].subsampledfastq)[0] + '.fa'
                    # Set the system call
                    sample[self.analysistype].reformatcall = 'reformat.sh in={fastq} out={fasta}'\
                        .format(fastq=sample[self.analysistype].subsampledfastq,
                                fasta=sample[self.analysistype].fasta)
                    # Add the sample to the queue
                    self.fastaqueue.put(sample)
        self.fastaqueue.join()
574342
def _convert_fastq(srafn, outdir, single=False):
    ""
    cmd = "fastq-dump --split-files --gzip {srafn}"
    cmd = "%s %s" % (utils.local_path_export(), cmd)
    sraid = os.path.basename(utils.splitext_plus(srafn)[0])
    if not srafn:
        return None
    if not single:
        out_file = [os.path.join(outdir, "%s_1.fastq.gz" % sraid),
                    os.path.join(outdir, "%s_2.fastq.gz" % sraid)]
        if not utils.file_exists(out_file[0]):
            with utils.chdir(outdir):
                do.run(cmd.format(**locals()), "Covert to fastq %s" % sraid)
        if not utils.file_exists(out_file[0]):
            raise IOError("SRA %s didn't convert, something happened." % srafn)
        return [out for out in out_file if utils.file_exists(out)]
    else:
        raise ValueError("Not supported single-end sra samples for now.")
1003084
def createfastq(self):
        """"""
        # Initialise samplecount
        samplecount = 0
        # If the fastq destination folder is not provided, make the default value of :path/:miseqfoldername
        self.fastqdestination = self.fastqdestination if self.fastqdestination else self.path + self.miseqfoldername
        # Make the path
        make_path(self.fastqdestination)
        # Initialise variables for storing index information
        index = ''
        indexlength = int()
        # bcl2fastq requires an older version of the sample sheet, this recreates the required version
        # Create the new sample sheet
        with open('{}/SampleSheet_modified.csv'.format(self.fastqdestination), "w") as modifiedsamplesheet:
            # Write the required headings to the file
            modifiedsamplesheet.write(
                "FCID,Lane,SampleID,SampleRef,Index,Description,Control,Recipe,Operator,SampleProject\n")
            for strain in self.samples:
                # Create a combined index of index1-index2
                try:
                    strain.run.modifiedindex = '{}-{}'.format(strain.run.index, strain.run.index2)
                    indexlength = 16
                    index = 'I8,I8'
                except KeyError:
                    strain.run.modifiedindex = strain.run.index
                    indexlength = 6
                    index = 'I6'
                # The list of items to print to each line of the modified sample sheet
                printlist = [self.flowcell, '1', strain.name, str(strain.run.SampleNumber), strain.run.modifiedindex,
                             strain.run.Description, 'N', 'NA',
                             strain.run.InvestigatorName, self.projectname]
                modifiedsamplesheet.write('{}\n'.format(",".join(printlist)))
                samplecount += 1
        # Set :forward/reverse length to :header.forward/reverse length if the argument is not provided, or it's 'full',
        # otherwise  use the supplied argument
        self.forwardlength = self.metadata.header.forwardlength if self.forwardlength.lower()\
            == 'full' else self.forwardlength
        # Set :reverselength to :header.reverselength
        self.reverselength = self.metadata.header.reverselength if self.reverselength.lower() \
            == 'full' else self.reverselength
        # As the number of cycles required is the number of forward reads + the index(8) + the second index(8)
        # Also set the basemask variable as required
        if self.reverselength != '0':
            self.readsneeded = int(self.forwardlength) + int(self.reverselength) + indexlength
            basemask = "Y{}n*,{},Y{}n*".format(self.forwardlength, index, self.reverselength)
            nohup = "nohup make -j 16 > nohup.out"
        else:
            #  + 1
            self.readsneeded = int(self.forwardlength) + indexlength
            basemask = "Y{}n*,{},n*".format(self.forwardlength, index)
            nohup = "nohup make -j 16 r1 > nohup.out"
        # Handle plurality appropriately
        samples = 'samples' if samplecount > 1 else 'sample'
        number = 'are' if samplecount > 1 else 'is'
        printtime('There {} {} {} in this run. '
                  'Running fastq creating module with the following parameters:\n'
                  'MiSeqPath: {},\n'
                  'MiSeqFolder: {},\n'
                  'Fastq destination: {},\n'
                  'SampleSheet: {}'
                  .format(number, samplecount, samples, self.miseqpath, self.miseqfolder,
                          self.fastqdestination, '{}/SampleSheet_modified.csv'.format(self.fastqdestination)),
                  self.start)
        # Count the number of completed cycles in the run of interest
        cycles = glob('{}Data/Intensities/BaseCalls/L001/C*'.format(self.miseqfolder))
        while len(cycles) < self.readsneeded:
            printtime('Currently at {} cycles. Waiting until the MiSeq reaches cycle {}'.format(len(cycles),
                      self.readsneeded), self.start)
            sleep(1800)
            cycles = glob('{}Data/Intensities/BaseCalls/L001/C*'.format(self.miseqfolder))
        # configureBClToFastq requires :self.miseqfolder//Data/Intensities/BaseCalls/config.xml in order to work
        # When you download runs from BaseSpace, this file is not provided. There is an empty config.xml file that
        # can be populated with run-specific values and moved to the appropriate folder
        if not os.path.isfile('{}Data/Intensities/BaseCalls/config.xml'.format(self.miseqfolder)):
            self.configfilepopulator()
        # Define the bcl2fastq system call
        bclcall = "configureBclToFastq.pl --input-dir {}Data/Intensities/BaseCalls " \
                  "--output-dir {} --force --sample-sheet {}/SampleSheet_modified.csv " \
                  "--mismatches 1 --no-eamss --fastq-cluster-count 0 --compression none --use-bases-mask {}"\
            .format(self.miseqfolder, self.fastqdestination, self.fastqdestination, basemask)
        # Define the nohup system call
        nohupcall = "cd {} && {}".format(self.fastqdestination, nohup)
        # fnull = open(os.devnull, 'wb')
        if not os.path.isdir("{}/Project_{}".format(self.fastqdestination, self.projectname)):
            # Call configureBclToFastq.pl
            printtime('Running bcl2fastq', self.start)
            # Run the commands
            threadlock = threading.Lock()
            outstr = ''
            outerr = ''
            out, err = run_subprocess(bclcall)
            outstr += out
            outerr += out
            out, err = run_subprocess(nohupcall)
            outstr += out
            outerr += out
            # call(bclcall, shell=True, stdout=fnull, stderr=fnull)
            # call(nohupcall, shell=True, stdout=fnull, stderr=fnull)
            threadlock.acquire()
            write_to_logfile(bclcall, bclcall, self.logfile)
            write_to_logfile(nohupcall, nohupcall, self.logfile)
            write_to_logfile(outstr, outerr, self.logfile)
            threadlock.release()
        # Populate the metadata
        for sample in self.metadata.samples:
            sample.commands = GenObject()
            sample.commands.nohup = nohupcall
            sample.commands.bcl = bclcall
            sample.run.forwardlength = self.forwardlength
            sample.run.reverselength = self.reverselength
        # Copy the fastq files to a central folder so they can be processed
        self.fastqmover()
993266
def write_fastq(filename):
    
    if filename:
        if filename.endswith('gz'):
            filename_fh = gzip.open(filename, mode='wb')
        else:
            filename_fh = open(filename, mode='w')
    else:
        filename_fh = None
    return filename_fh
62368
def fastq(args):
    
    from jcvi.formats.fastq import FastqLite

    p = OptionParser(fastq.__doc__)
    p.add_option("--qv", type="int",
                 help="Use generic qv value [dafault: %default]")

    opts, args = p.parse_args(args)

    if len(args) != 1:
        sys.exit(not p.print_help())

    fastafile, = args
    fastqfile = fastafile.rsplit(".", 1)[0] + ".fastq"
    fastqhandle = open(fastqfile, "w")
    num_records = 0

    if opts.qv is not None:
        qv = chr(ord('!') + opts.qv)
        logging.debug("QV char '{0}' ({1})".format(qv, opts.qv))
    else:
        qv = None

    if qv:
        f = Fasta(fastafile, lazy=True)
        for name, rec in f.iteritems_ordered():
            r = FastqLite("@" + name, str(rec.seq).upper(), qv * len(rec.seq))
            print(r, file=fastqhandle)
            num_records += 1

    else:
        qualfile = get_qual(fastafile)
        for rec in iter_fasta_qual(fastafile, qualfile):
            SeqIO.write([rec], fastqhandle, "fastq")
            num_records += 1

    fastqhandle.close()
    logging.debug("A total of %d records written to `%s`" % \
            (num_records, fastqfile))
604051
def scrobble_data_dir(dataDir, sampleMap, outF, qualF=None, idopt=None,
                      utf16=False):
    
    seqcount = 0
    outfiles = [osp.split(outF.name)[1]]
    if qualF:
        outfiles.append(osp.split(qualF.name)[1])

    for item in os.listdir(dataDir):
        if item in outfiles or not osp.isfile(os.path.join(dataDir, item)):
            continue
        # FASTA files
        if osp.splitext(item)[1] in file_types['fasta']:
            fh = open_enc(os.path.join(dataDir, item), utf16)
            records = SeqIO.parse(fh, 'fasta')
            for record in records:
                if isinstance(idopt, tuple):
                    sep, field = idopt
                    sampleID = record.id.split(sep)[field - 1]
                else:
                    sampleID = osp.splitext(item)[0]
                record.seq = (sampleMap[sampleID].barcode +
                              sampleMap[sampleID].primer +
                              record.seq)
                SeqIO.write(record, outF, 'fasta')
                seqcount += 1
            fh.close()
        # QUAL files
        elif qualF and osp.splitext(item)[1] in file_types['qual']:
            fh = open_enc(os.path.join(dataDir, item), utf16)
            records = SeqIO.parse(fh, 'qual')
            for record in records:
                mi = sampleMap[sampleMap.keys()[0]]
                quals = [40 for _ in range(len(mi.barcode) + len(mi.primer))]
                record.letter_annotations['phred_quality'][0:0] = quals
                SeqIO.write(record, qualF, 'qual')
            fh.close()
    return seqcount
1053939
def space_to_folders(self, current_result_list, current_query, param_space,
                         runs, current_directory):
        
        # Base case: we iterate over the runs and copy files in the final
        # directory.
        if not param_space:
            for run, r in enumerate(current_result_list[:runs]):
                files = self.db.get_result_files(r)
                new_dir = os.path.join(current_directory, "run=%s" % run)
                os.makedirs(new_dir, exist_ok=True)
                for filename, filepath in files.items():
                    shutil.copyfile(filepath, os.path.join(new_dir, filename))
            return

        [key, value] = list(param_space.items())[0]
        # Iterate over dictionary values
        for v in value:
            next_query = deepcopy(current_query)
            temp_query = deepcopy(current_query)

            # For each list, recur 'fixing' that dimension.
            next_query[key] = v  # Update query

            # Create folder
            folder_name = ("%s=%s" % (key, v)).replace('/', '_')
            new_dir = os.path.join(current_directory, folder_name)
            os.makedirs(new_dir, exist_ok=True)

            next_param_space = deepcopy(param_space)
            del(next_param_space[key])

            temp_query[key] = v
            temp_result_list = [r for r in current_result_list if
                                self.satisfies_query(r, temp_query)]

            self.space_to_folders(temp_result_list, next_query,
                                  next_param_space, runs, new_dir)
742119
def download(self):
        
        self.downloaded_paths = list()
        for path in self.paths_for_download:
            downloaded_path = list()
            utils.mkdir_p(os.path.abspath(self.directory))

            sra_run = path.split("/")[-1]
            logger.info("Analysing %s" % sra_run)
            url = type(self).FTP_ADDRESS_TPL.format(
                range_subdir=sra_run[:6],
                file_dir=sra_run)
            logger.debug("URL: %s", url)
            filepath = os.path.abspath(
                os.path.join(self.directory, "%s.sra" % sra_run))
            utils.download_from_url(
                url,
                filepath,
                aspera=self.aspera,
                silent=self.silent,
                force=self.force)

            if self.filetype in ("fasta", "fastq"):
                if utils.which('fastq-dump') is None:
                    logger.error("fastq-dump command not found")
                ftype = ""
                if self.filetype == "fasta":
                    ftype = " --fasta "
                cmd = "fastq-dump"
                if utils.which('parallel-fastq-dump') is None:
                    cmd += " %s --outdir %s %s"
                else:
                    logger.debug("Using parallel fastq-dump")
                    cmd = " parallel-fastq-dump --threads %s"
                    cmd = cmd % self.threads
                    cmd += " %s --outdir %s -s %s"
                cmd = cmd % (ftype, self.directory, filepath)

                for fqoption, fqvalue in iteritems(self.fastq_dump_options):
                    if fqvalue:
                        cmd += (" --%s %s" % (fqoption, fqvalue))
                    elif fqvalue is None:
                        cmd += (" --%s" % fqoption)
                logger.debug(cmd)
                process = sp.Popen(cmd, stdout=sp.PIPE,
                                   stderr=sp.PIPE,
                                   shell=True)
                logger.info("Converting to %s/%s*.%s.gz\n" % (
                    self.directory, sra_run, self.filetype))
                pout, perr = process.communicate()
                downloaded_path = glob.glob(os.path.join(
                    self.directory,
                    "%s*.%s.gz" % (sra_run, self.filetype)))

            elif self.filetype == 'sra':
                downloaded_path = glob.glob(os.path.join(
                    self.directory,
                    "%s*.%s" % (sra_run, self.filetype)))

            else:
                downloaded_path = glob.glob(os.path.join(
                    self.directory,
                    "%s*" % sra_run))
                logger.error("Filetype %s not supported." % self.filetype)

            if not self.keep_sra and self.filetype != 'sra':
                # Delete sra file
                os.unlink(filepath)

            self.downloaded_paths += downloaded_path
        return self.downloaded_paths
130255
def _get_result_paths(self, data):
        """"""
        result = {}
        result['FASTA'] = ResultPath(Path=self._get_seqs_outfile())
        result['CLSTR'] = ResultPath(Path=self._get_clstr_outfile())
        return result
548696
def fastq_to_csv(in_file, fastq_format, work_dir):
    
    out_file = "%s.csv" % (os.path.splitext(os.path.basename(in_file))[0])
    out_file = os.path.join(work_dir, out_file)
    if not (os.path.exists(out_file) and os.path.getsize(out_file) > 0):
        with open(in_file) as in_handle:
            with open(out_file, "w") as out_handle:
                writer = csv.writer(out_handle)
                for rec in SeqIO.parse(in_handle, fastq_format):
                    writer.writerow([rec.id] + rec.letter_annotations["phred_quality"])
    return out_file
1367498
def _flatten_samples(samples, base_file, get_retriever):
    
    flat_data = []
    for data in samples:
        data["reference"] = _indexes_to_secondary_files(data["reference"], data["genome_build"])
        cur_flat = {}
        for key_path in [["analysis"], ["description"], ["rgnames"], ["config", "algorithm"],
                         ["metadata"], ["genome_build"], ["resources"],
                         ["files"], ["reference"], ["genome_resources"], ["vrn_file"]]:
            cur_key = "__".join(key_path)
            for flat_key, flat_val in _to_cwldata(cur_key, tz.get_in(key_path, data), get_retriever):
                cur_flat[flat_key] = flat_val
        flat_data.append(cur_flat)
    out = {}
    for key in sorted(list(set(reduce(operator.add, [list(d.keys()) for d in flat_data])))):
        # Periods in keys cause issues with WDL and some CWL implementations
        clean_key = key.replace(".", "_")
        out[clean_key] = []
        for cur_flat in flat_data:
            out[clean_key].append(cur_flat.get(key))
    # special case for back-compatibility with fasta specifications -- yuck
    if "reference__fasta__base" not in out and "reference__fasta" in out:
        out["reference__fasta__base"] = out["reference__fasta"]
        del out["reference__fasta"]
    return _samplejson_to_inputs(out), out