Skip to Content
GuidesInspecting files you have

Inspecting files you have

Someone has sent you a reference and a BAM and said they go together. This is how you find out, in one command, before you write anything.

ligase inspect is the only command that needs no pipeline. It loads each file you name, says what it read it as, prints every dimension it worked out along with where it read that from — and, given two or more files, compares them the way one step’s inputs are compared.

Nothing is executed. No step body runs, no tool is invoked, nothing is written and no cache appears. It reads headers.

One file

ligase inspect refs/genome.fasta
Reference refs/genome.fasta genome.fasta.reference = 2 contigs, 40 bp (from FASTA contigs: refs/genome.fasta) genome.fasta.contig_naming = bare (Ensembl/NCBI style) (from FASTA deflines: refs/genome.fasta) genome.fasta.organism is unknown (a FASTA does not record its organism; declare it) genome.fasta.release is unknown (a FASTA does not record which release it came from; declare it) coordinates, sample_set, pairing, quality_encoding, subject, source_set and identifier_namespace do not apply to a Reference. 1 file, so nothing to compare: two or more are compared the way one step's inputs are.

There are three states in there, and telling them apart is most of what the command is for.

A dimension with a value is shown with the value and where it came from. from FASTA deflines: refs/genome.fasta is the half that makes it actionable: you can go and look at that file rather than take Ligase’s word for it. See types and dimensions for what each dimension means.

A dimension that applies but has no value is shown with the reason, and the reason is usually an instruction. a FASTA does not record its organism; declare it is how you discover declaring dimensions. Sometimes it is an instruction to go and fix the file instead — a gene list whose symbols a spreadsheet has turned into dates says so, and says why declaring a namespace would be the wrong fix.

A dimension that does not apply to the kind is named once, on the last line, as not applying. A FASTA is not missing a quality encoding: it has no such property to have, and listing it as unknown would send you looking for a declaration that does not exist.

Two or more

ligase inspect refs/genome.fasta aln/sample01.bam

Each file gets its own block, and then the comparison:

ContigNamingError in step `inspect`: genome.fasta.contig_naming = bare (Ensembl/NCBI style) (from FASTA deflines: refs/genome.fasta) sample01.bam.contig_naming = chr-prefixed (UCSC style) (from SAM @SQ header: aln/sample01.bam) The contigs are otherwise identical. Add a renaming step, or use one naming style throughout. 2 files, compared on reference and contig_naming: 1 disagreement.

The full transcript, from a real run, is on the quickstart.

Two things in that output are worth knowing about.

The diagnostic’s lines are the lines from the blocks above it. There is one renderer, so an error never describes a file in different words from the description you just read — it quotes them.

The heading says in step \inspect`. There is no step: inspect` ran the comparison a step’s inputs get, outside any pipeline, and it names itself as the thing that did the comparing. The error is otherwise the one a pipeline would have printed, which is deliberate — it is the same code, so this diagnostic cannot drift from the one you get later.

What the verdict covers

The last line names the dimensions at least two of the files state a value for, and reading it matters:

2 files, but nothing was compared: no dimension is stated by two of them.

A FASTQ and a BED share no dimension either of them records. They do not agree; there was nothing to agree about, and a bare “no disagreement” would be false comfort. Declare what the files cannot say about themselves and there will be something to compare.

A dimension nothing states can still be a disagreement. Two gene lists that each say nothing about their identifier space do not pass: identifier_namespace is demanded where two of them are joined, because two lists agreeing by silence is exactly the failure the dimension exists for. That is an UndeclaredDimensionError, and a finding like any other.

Exit codes

inspect is built to go in a shell pipeline, so the exit code carries the answer and you never have to parse the output.

CodeMeans
0every file read, and nothing disagrees
1every file read, and they disagree
2a file could not be read, so there is no verdict
# Refuse to start a run over files that do not agree. ligase inspect refs/genome.fasta aln/*.bam && snakemake --cores 8

The difference between 1 and 2 is the one worth having. A file that could not be read has no verdict at all, so a 2 withholds the comparison rather than giving you one over whichever files happened to load — a clean bill of health over two of three files reads as a clean bill of health over all three. The files that did load are still described, and every file that did not is named on standard error with the engine’s reason.

What it reads

The loader is chosen by extension, with a .gz or .bgz suffix ignored:

ExtensionsRead as
.fasta .fa .fnaReference
.fastq .fqReads
.sam .bamAlignment
.vcfVariants
.bed .gff .gff3 .gtfIntervals
.tsvEntitySet, or MoleculeSet — see below

Anything else is a file it cannot read: exit 2, naming the extensions it knows.

.tsv is the one suffix that cannot settle it, so the header does: a table with an inchikey column is a MoleculeSet, a table with a smiles column and no id is one too, and anything else is an EntitySet. A table of structures — what a generative model emits, and what lg.chem.standardize takes — therefore inspects as a molecule set whose representation is SMILES, as given. A file with both id and smiles is read as the entity set it most likely is: a list of genes may carry a structure as an attribute, while a molecule table has no reason to carry an identifier column. In a pipeline you say what a file is by calling the loader for it — lg.reference(...), lg.entity_set(...) — and inspect is the one surface with nobody to ask.

What it does not do

inspect takes no declaration flags, and that is on purpose. A dimension a file cannot record comes back unknown with the reason, which is the honest answer and also the useful one: it tells you what there is to declare and where. Declaring happens where you load the data, in the pipeline, so that the declaration is recorded in provenance and hashed into the cache key rather than typed at a prompt and forgotten.

It also never pairs files up. Two FASTQs named sample_1.fastq and sample_2.fastq are inspected as two files, not as one paired sample — though both report the sample as sample, because the mate suffix is not part of a sample’s name. Grouping mates is lg.samples()’s job, and it is a job with a wrong answer worth refusing rather than guessing at.

Next

Last updated on