fastq-sheet-audit 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. fastq_sheet_audit-0.2.0/LICENSE +21 -0
  2. fastq_sheet_audit-0.2.0/PKG-INFO +304 -0
  3. fastq_sheet_audit-0.2.0/README.md +288 -0
  4. fastq_sheet_audit-0.2.0/pyproject.toml +40 -0
  5. fastq_sheet_audit-0.2.0/setup.cfg +4 -0
  6. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/__init__.py +1 -0
  7. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/adjudication.py +107 -0
  8. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/assets/app_icon.png +0 -0
  9. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/cli.py +120 -0
  10. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/column_mapping.py +117 -0
  11. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/export_io.py +112 -0
  12. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/export_plan.py +126 -0
  13. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/gui.py +922 -0
  14. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/gui_controller.py +399 -0
  15. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/inventory.py +84 -0
  16. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/naming.py +66 -0
  17. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/output.py +62 -0
  18. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/pairing.py +120 -0
  19. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/pathmap.py +108 -0
  20. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/portability.py +44 -0
  21. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/presentation.py +128 -0
  22. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/profile_data/__init__.py +1 -0
  23. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/profile_data/generic.json +16 -0
  24. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/profile_data/nfcore-methylseq-4.2.0.json +17 -0
  25. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/profile_data/nfcore-rnaseq-3.27.0.json +23 -0
  26. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/profile_data/nfcore-smrnaseq-2.4.1.json +16 -0
  27. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/profile_data/nfcore-viralrecon-3.0.0-illumina.json +16 -0
  28. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/profile_data/nfcore-viralrecon-3.0.0-nanopore.json +15 -0
  29. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/profile_validation.py +82 -0
  30. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/profiles.py +177 -0
  31. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/read_mode.py +120 -0
  32. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/reconciliation.py +198 -0
  33. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/report_io.py +20 -0
  34. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/report_serialization.py +160 -0
  35. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/reporting.py +229 -0
  36. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/serialization.py +39 -0
  37. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/sheet.py +91 -0
  38. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit/workflow.py +108 -0
  39. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit.egg-info/PKG-INFO +304 -0
  40. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit.egg-info/SOURCES.txt +67 -0
  41. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit.egg-info/dependency_links.txt +1 -0
  42. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit.egg-info/entry_points.txt +5 -0
  43. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit.egg-info/requires.txt +3 -0
  44. fastq_sheet_audit-0.2.0/src/fastq_sheet_audit.egg-info/top_level.txt +1 -0
  45. fastq_sheet_audit-0.2.0/tests/test_adjudication.py +209 -0
  46. fastq_sheet_audit-0.2.0/tests/test_cli.py +433 -0
  47. fastq_sheet_audit-0.2.0/tests/test_column_mapping.py +161 -0
  48. fastq_sheet_audit-0.2.0/tests/test_export_io.py +198 -0
  49. fastq_sheet_audit-0.2.0/tests/test_export_plan.py +197 -0
  50. fastq_sheet_audit-0.2.0/tests/test_gui.py +1113 -0
  51. fastq_sheet_audit-0.2.0/tests/test_gui_controller.py +758 -0
  52. fastq_sheet_audit-0.2.0/tests/test_inventory.py +152 -0
  53. fastq_sheet_audit-0.2.0/tests/test_naming.py +79 -0
  54. fastq_sheet_audit-0.2.0/tests/test_output.py +161 -0
  55. fastq_sheet_audit-0.2.0/tests/test_pairing.py +231 -0
  56. fastq_sheet_audit-0.2.0/tests/test_pathmap.py +132 -0
  57. fastq_sheet_audit-0.2.0/tests/test_portability.py +133 -0
  58. fastq_sheet_audit-0.2.0/tests/test_presentation.py +187 -0
  59. fastq_sheet_audit-0.2.0/tests/test_profile_validation.py +171 -0
  60. fastq_sheet_audit-0.2.0/tests/test_profiles.py +693 -0
  61. fastq_sheet_audit-0.2.0/tests/test_read_mode.py +166 -0
  62. fastq_sheet_audit-0.2.0/tests/test_reconciliation.py +206 -0
  63. fastq_sheet_audit-0.2.0/tests/test_report_io.py +146 -0
  64. fastq_sheet_audit-0.2.0/tests/test_report_serialization.py +185 -0
  65. fastq_sheet_audit-0.2.0/tests/test_reporting.py +192 -0
  66. fastq_sheet_audit-0.2.0/tests/test_serialization.py +118 -0
  67. fastq_sheet_audit-0.2.0/tests/test_sheet.py +112 -0
  68. fastq_sheet_audit-0.2.0/tests/test_text_atomic.py +219 -0
  69. fastq_sheet_audit-0.2.0/tests/test_workflow.py +248 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Domathoti Sandy Richard
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,304 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastq-sheet-audit
3
+ Version: 0.2.0
4
+ Summary: Local FASTQ/sample-sheet auditing with explicit, validated sample-sheet export
5
+ Author: dr-richard
6
+ License-Expression: MIT
7
+ Keywords: bioinformatics,fastq,samplesheet,validation,sequencing
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=8; extra == "dev"
15
+ Dynamic: license-file
16
+
17
+ # fastq-sheet-audit
18
+
19
+ <p align="center">
20
+ <img src="src/fastq_sheet_audit/assets/app_icon.png"
21
+ alt="fastq-sheet-audit icon"
22
+ width="128">
23
+ </p>
24
+
25
+ A local, offline FASTQ ↔ sample-sheet preflight tool with a command-line audit,
26
+ a native desktop GUI, and explicit, validated sample-sheet export.
27
+
28
+ This README describes **fastq-sheet-audit v0.2.0**. The historical v0.1
29
+ prototype is preserved in Git under the `v0.1.0` tag.
30
+
31
+ ## Why this exists
32
+
33
+ A sequencing workflow can fail before analysis begins because a sheet points to
34
+ missing files, mixes lanes or chunks, assigns the same FASTQ twice, or leaves
35
+ files unaccounted for. fastq-sheet-audit makes those discrepancies visible
36
+ before a downstream pipeline runs. It separates discovered evidence, automatic
37
+ interpretation, and explicit human decisions.
38
+
39
+ ## Capabilities and design
40
+
41
+ - Lossless CSV/TSV import, deterministic column mapping, and recursive FASTQ inventory.
42
+ - Structural filename parsing, exact mate identities, and explicit read-layout checks.
43
+ - Findings for missing/reused files, role/sample/pair disagreements, and unlisted files.
44
+ - Case-portability diagnostics and GUI pairing adjudication without destroying evidence.
45
+ - Declarative export profiles, manual metadata editing, path previews, and CSV/TSV exports.
46
+ - Structured JSON audit reports for machine consumers.
47
+
48
+ The application is fully local/offline: **no telemetry, cloud/API dependency,
49
+ or AI/LLM dependency**. It uses filename structure and filesystem metadata;
50
+ FASTQ sequence contents are never opened or read. Interpretation is deterministic,
51
+ with no fuzzy matching or biological inference from filenames. Ambiguity stays
52
+ visible until an explicit decision is made.
53
+
54
+ FASTQs and input sample sheets are never renamed, moved, deleted, repaired, or
55
+ modified. Auditing leaves inputs untouched; explicit report/export actions can
56
+ create output files. Publication protects the input sheet, raw discovered FASTQs,
57
+ and referenced FASTQ paths, including references outside the scan root and
58
+ missing referenced destinations. Resolved aliases and existing symlink/hardlink
59
+ aliases are checked too.
60
+
61
+ Outputs use a temporary file in the destination directory, UTF-8 validation,
62
+ flush/fsync, and atomic replacement. Overwrite is conservative: CLI reports
63
+ require `--overwrite-report` to replace an ordinary file; GUI exports currently
64
+ refuse existing destinations. Protection remains active even with report overwrite.
65
+ No-overwrite publication reserves the destination exclusively before replacement.
66
+ An empty reservation can briefly be visible. Python's portable APIs do not offer
67
+ an atomic conditional replace, so hostile concurrent directory/path changes or
68
+ replacement of that reservation cannot be fully guarded against. This is
69
+ best-effort race safety, not a guarantee against concurrent filesystem mutation.
70
+
71
+ ## Installation
72
+
73
+ Python 3.10 or newer is required. From a checkout of the v0.2 development branch:
74
+
75
+ ```bash
76
+ python -m pip install .
77
+ fastq-sheet-audit --version
78
+ ```
79
+
80
+ The GUI uses standard-library tkinter/ttk and needs an available Tk installation
81
+ and desktop display. Some Python distributions provide Tk separately. CLI use
82
+ does not require opening the GUI. Dependency installation may use the network;
83
+ audits and exports do not.
84
+
85
+ ## CLI quick start
86
+
87
+ Input sheets may be UTF-8 CSV or TSV, including a UTF-8 BOM, quoted fields,
88
+ LF, and CRLF. Headers, column order, cell text, and physical row numbers are
89
+ preserved. Duplicate headers after surrounding-whitespace trimming, surplus
90
+ fields, malformed quoting, and missing headers are rejected. Short rows receive
91
+ empty trailing cells; only entirely empty rows are skipped.
92
+
93
+ Example `samples.csv`:
94
+
95
+ ```csv
96
+ sample,r1,r2
97
+ A,A_S1_L001_R1_001.fastq.gz,A_S1_L001_R2_001.fastq.gz
98
+ A,A_S1_L002_R1_001.fastq.gz,A_S1_L002_R2_001.fastq.gz
99
+ ```
100
+
101
+ ```bash
102
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq
103
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq --read-mode paired --json audit.json
104
+ ```
105
+
106
+ Relative FASTQ references resolve against `--fastq-dir`, including subdirectories,
107
+ not against the sheet's directory. Absolute references remain absolute. Path
108
+ cell text is used without trimming, variable expansion, or rewriting.
109
+ Discovery recognizes `.fastq.gz`, `.fq.gz`, `.fastq`, and `.fq`, case-insensitively.
110
+ Directory symlinks are not traversed recursively; eligible file symlinks may be
111
+ inventoried.
112
+
113
+ The CLI prints a deterministic summary and ordered findings. Available options:
114
+
115
+ | Option | Meaning |
116
+ | --- | --- |
117
+ | `--read-mode {auto,paired,single}` | Requested layout; default `auto` |
118
+ | `--sample-column N` | Explicit SAMPLE column, **1-based** |
119
+ | `--r1-column N` | Explicit R1 column, **1-based** |
120
+ | `--r2-column N` | Explicit R2 column, **1-based** |
121
+ | `--no-r2-column` | Explicitly leave R2 unmapped |
122
+ | `--json PATH` | Write a structured JSON audit report |
123
+ | `--overwrite-report` | Opt in to replacement of an ordinary JSON report file |
124
+
125
+ ## Column mapping
126
+
127
+ Automatic mapping compares headers using surrounding-whitespace trimming and
128
+ Unicode casefold only. The deterministic aliases are:
129
+
130
+ | Role | Aliases |
131
+ | --- | --- |
132
+ | SAMPLE | `sample`, `sample_id`, `sampleid` |
133
+ | R1 | `r1`, `fastq_1`, `fastq1`, `read1`, `read_1` |
134
+ | R2 | `r2`, `fastq_2`, `fastq2`, `read2`, `read_2` |
135
+
136
+ SAMPLE and R1 are required; R2 is optional. Multiple candidates for any role
137
+ are refused unless explicitly resolved, including an ambiguous optional R2.
138
+ Errors list physical column numbers and exact headers. Overrides can select
139
+ non-alias headers; omitted overrides retain automatic mapping. One physical
140
+ column cannot fill multiple roles. R2 selection and unmapping are mutually
141
+ exclusive.
142
+
143
+ For a sheet with `specimen,forward,reverse`:
144
+
145
+ ```bash
146
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq --sample-column 1 --r1-column 2 --r2-column 3
147
+ ```
148
+
149
+ The GUI's **Load columns** action offers indexed choices, **Automatic**, and
150
+ **Unassigned**. Leaving SAMPLE or R1 unassigned prevents auditing. Unknown
151
+ metadata columns survive import; profile exports contain the selected profile's
152
+ columns rather than automatically copying arbitrary source metadata.
153
+
154
+ ## Read modes, pairing, and findings
155
+
156
+ | Mode | Behavior |
157
+ | --- | --- |
158
+ | `auto` | Complete biological pairs classify as paired; R1-only groups classify as single. Mixed, orphaned, ambiguous, or empty biological evidence is unresolved with a warning. |
159
+ | `paired` | Every pairable R1/R2 needs its exact mate. Missing mates and duplicate-role ambiguity are errors. |
160
+ | `single` | R1 needs no mate; biological R2 presence is reported explicitly as an error. |
161
+
162
+ Index reads, Undetermined files, and unparsed names remain visible and are
163
+ excluded from biological layout inference. The parser recognizes common forms
164
+ such as `A_R1.fastq.gz`, `A_1.fastq`, `A_S1_L001_R1_001.fastq.gz`, and
165
+ `A_I1_001.fastq.gz`; it does not claim exhaustive naming support.
166
+
167
+ Mate identity includes sample, sample number, lane, chunk, read style, suffix,
168
+ and relative parent directory. **Only sample and suffix use Unicode casefold.**
169
+ Lane/sample-number/chunk differences and R-style versus bare `1/2` remain
170
+ significant. Directory identity preserves exact spelling through a
171
+ platform-independent representation: `Run/A_R1.fastq` and `run/A_R2.fastq`
172
+ are separate identities. Files are never paired by list position or proximity.
173
+
174
+ Repeated sample IDs are allowed when rows use distinct FASTQ evidence, as in the
175
+ two-lane example. Actual file reuse, including filesystem aliases, is an error
176
+ (`FASTQ_REUSED`). Sample-versus-filename comparison trims surrounding sheet
177
+ sample whitespace and uses Unicode casefold only: `A-B` and `AB` remain distinct.
178
+ Original text is retained.
179
+
180
+ An omitted optional R2 is **not** automatically assigned. If an exact R2 exists
181
+ on disk but is absent from the sheet, it remains `UNLISTED_FASTQ` evidence.
182
+ Unknown/unparsed filenames are retained, not guessed. Filename role disagreements,
183
+ structural pair mismatches, and missing references are reported. Case-only
184
+ relative-path collisions are warnings; this is a case-portability check, not a
185
+ complete set of Windows filename rules.
186
+
187
+ ## GUI quick start and adjudication
188
+
189
+ ```bash
190
+ fastq-sheet-audit-gui
191
+ ```
192
+
193
+ Choose a FASTQ directory and sheet, load/resolve columns if needed, select a
194
+ read mode, and press **Audit**. Opening the GUI does not scan inputs automatically.
195
+ Summary, Findings, FASTQ Inventory, and Pairing / Adjudication tabs expose the
196
+ current evidence.
197
+
198
+ Select a pair row to choose R1/R2 candidates explicitly, leave a role
199
+ **Unassigned**, or **Reset automatic**. **Confirmed** records human confirmation;
200
+ it does not resolve ambiguity or override errors. Applying a decision revalidates
201
+ the workflow. All original candidates remain in the evidence even after a
202
+ selection or unassignment. Unresolved automatic choices remain unresolved.
203
+
204
+ Read-layout checks use effective adjudicated reads, while reconciliation and
205
+ case-collision checks retain raw inventory. Decisions cannot suppress unrelated
206
+ findings. The tool does not edit the source sheet to repair discrepancies;
207
+ correct it externally and rerun Audit when necessary. Changed inputs require a
208
+ new audit, and changed export options require a fresh preview.
209
+
210
+ ## Export profiles and manual metadata
211
+
212
+ GUI export requires a clean workflow, followed by a valid profile preview.
213
+ Choose a profile and path mode, set any needed manual fields per source row,
214
+ then press **Preview export**. Choose CSV or TSV and a destination explicitly
215
+ before pressing **Export**. Format is independent of filename extension.
216
+ The CLI audits and publishes JSON reports; it does not export sample sheets.
217
+
218
+ Export uses exact source sample text and effective adjudicated R1/R2 records,
219
+ not the original sheet's FASTQ path cells after adjudication. Profile columns
220
+ declare their source roles. Columns with no source role are manual:
221
+ no metadata is inferred and no descriptive profile defaults are automatically
222
+ inserted. **Set** supplies exact text, including an explicit empty string;
223
+ **Clear** makes the value absent. Unapplied editor text must be applied or
224
+ cleared before preview/export.
225
+
226
+ Validation distinguishes a required column from a required cell. String allowed
227
+ values are matched exactly without trimming or casefolding. Integer values use
228
+ an optional sign and ASCII decimal digits; text such as `01` remains unchanged
229
+ in output. Whitespace, Unicode, punctuation, and formula-like text are preserved;
230
+ CSV/TSV export is not a spreadsheet-sanitization step.
231
+
232
+ Bundled profiles are local declarative contracts, not a guarantee that every
233
+ pipeline option or future release is supported:
234
+
235
+ | Profile ID | Contract / manual fields |
236
+ | --- | --- |
237
+ | `generic` | `sample,r1`; optional `r2`. No pipeline compatibility claim. |
238
+ | `nfcore-rnaseq-3.27.0` | `sample,fastq_1,fastq_2,strandedness`. Strandedness requires an explicit exact value: `forward`, `reverse`, `unstranded`, or `auto`; no automatic default. |
239
+ | `nfcore-methylseq-4.2.0` | `sample,fastq_1,fastq_2,genome`. Genome is manual and may be empty. |
240
+ | `nfcore-smrnaseq-2.4.1` | `sample,fastq_1`; optional `fastq_2`. Profile notes say downstream small-RNA processing primarily uses R1; this tool does not silently discard R2. |
241
+ | `nfcore-viralrecon-3.0.0-illumina` | Illumina-only: `sample,fastq_1,fastq_2`. |
242
+ | `nfcore-viralrecon-3.0.0-nanopore` | Nanopore-only **barcode mapping**, `sample,barcode`; barcode is a manual integer. Metadata/editor are available, but FASTQ audit sessions cannot preview or publish this profile. Nanopore FASTQs are supplied separately by the pipeline's directory layout. |
243
+
244
+ All five FASTQ-samplesheet profiles support single-end input. For rnaseq,
245
+ methylseq, and viralrecon Illumina, `fastq_2` is a required **column** but may
246
+ contain empty cells. Generic and smrnaseq omit their optional R2 column when no
247
+ row supplies an effective R2. Methylseq's `genome` column is required but its
248
+ value is optional. Viralrecon's downstream sample-name rewriting is not
249
+ reproduced here: sample IDs are not silently renamed or normalized.
250
+
251
+ ## Export path modes
252
+
253
+ | GUI mode | Rendering |
254
+ | --- | --- |
255
+ | Local absolute | Original local absolute inventory path |
256
+ | Relative to FASTQ root | Inventory relative path in local/platform form |
257
+ | Rebased root | Relative components joined to an explicit target root |
258
+
259
+ Rebasing requires an explicit **POSIX** or **Windows** style and an absolute
260
+ root in that style. It uses pure path transformations without accessing the
261
+ target filesystem. Spaces and Unicode remain intact; unsafe relative components
262
+ are rejected rather than resolved away.
263
+
264
+ ## JSON reports and exit codes
265
+
266
+ ```bash
267
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq --json audit.json
268
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq --json audit.json --overwrite-report
269
+ ```
270
+
271
+ JSON reports use `schema_version: 1`, independently of the package version.
272
+ They preserve structured inventory, reconciliation findings and assignments,
273
+ read-mode diagnostics and evidence, case collisions, and pair candidates,
274
+ decisions, effective/unresolved records, and confirmation. Pair keys remain
275
+ structured, absent values stay null, and Unicode remains literal. Ordering is
276
+ deterministic. A report can be written even when the audit has findings;
277
+ a publication failure instead returns exit 2.
278
+
279
+ | CLI exit | Meaning |
280
+ | --- | --- |
281
+ | `0` | Audit completed with no findings |
282
+ | `1` | Audit completed with findings, including warnings or errors |
283
+ | `2` | Expected invalid input, filesystem, or report-publication failure; argparse also uses 2 for invalid command usage |
284
+
285
+ Unexpected programmer errors are not converted into ordinary audit failures.
286
+
287
+ ## Scope and development
288
+
289
+ This is a filename/path/sample-sheet preflight tool. It does not inspect read
290
+ contents, compare read counts, validate checksums, demultiplex, repair FASTQs,
291
+ run pipelines, infer biological metadata, or provide clinical validation.
292
+ Profile exports cover only the bundled declarative fields. CLI human pairing
293
+ adjudication and barcode-workflow export are outside the current scope.
294
+
295
+ ```bash
296
+ python -m pip install -e ".[dev]"
297
+ python -m pytest -q
298
+ ```
299
+
300
+ Tests are headless; they do not launch Tk. CI covers Ubuntu Python 3.10–3.14,
301
+ representative Python 3.12 jobs on Windows/macOS, and isolated sdist/wheel,
302
+ entry-point, and profile-resource validation. See [CHANGELOG.md](CHANGELOG.md)
303
+ for the v0.2.0 changes and historical 0.1.0 entry, and
304
+ [SECURITY.md](SECURITY.md) for security reporting.
@@ -0,0 +1,288 @@
1
+ # fastq-sheet-audit
2
+
3
+ <p align="center">
4
+ <img src="src/fastq_sheet_audit/assets/app_icon.png"
5
+ alt="fastq-sheet-audit icon"
6
+ width="128">
7
+ </p>
8
+
9
+ A local, offline FASTQ ↔ sample-sheet preflight tool with a command-line audit,
10
+ a native desktop GUI, and explicit, validated sample-sheet export.
11
+
12
+ This README describes **fastq-sheet-audit v0.2.0**. The historical v0.1
13
+ prototype is preserved in Git under the `v0.1.0` tag.
14
+
15
+ ## Why this exists
16
+
17
+ A sequencing workflow can fail before analysis begins because a sheet points to
18
+ missing files, mixes lanes or chunks, assigns the same FASTQ twice, or leaves
19
+ files unaccounted for. fastq-sheet-audit makes those discrepancies visible
20
+ before a downstream pipeline runs. It separates discovered evidence, automatic
21
+ interpretation, and explicit human decisions.
22
+
23
+ ## Capabilities and design
24
+
25
+ - Lossless CSV/TSV import, deterministic column mapping, and recursive FASTQ inventory.
26
+ - Structural filename parsing, exact mate identities, and explicit read-layout checks.
27
+ - Findings for missing/reused files, role/sample/pair disagreements, and unlisted files.
28
+ - Case-portability diagnostics and GUI pairing adjudication without destroying evidence.
29
+ - Declarative export profiles, manual metadata editing, path previews, and CSV/TSV exports.
30
+ - Structured JSON audit reports for machine consumers.
31
+
32
+ The application is fully local/offline: **no telemetry, cloud/API dependency,
33
+ or AI/LLM dependency**. It uses filename structure and filesystem metadata;
34
+ FASTQ sequence contents are never opened or read. Interpretation is deterministic,
35
+ with no fuzzy matching or biological inference from filenames. Ambiguity stays
36
+ visible until an explicit decision is made.
37
+
38
+ FASTQs and input sample sheets are never renamed, moved, deleted, repaired, or
39
+ modified. Auditing leaves inputs untouched; explicit report/export actions can
40
+ create output files. Publication protects the input sheet, raw discovered FASTQs,
41
+ and referenced FASTQ paths, including references outside the scan root and
42
+ missing referenced destinations. Resolved aliases and existing symlink/hardlink
43
+ aliases are checked too.
44
+
45
+ Outputs use a temporary file in the destination directory, UTF-8 validation,
46
+ flush/fsync, and atomic replacement. Overwrite is conservative: CLI reports
47
+ require `--overwrite-report` to replace an ordinary file; GUI exports currently
48
+ refuse existing destinations. Protection remains active even with report overwrite.
49
+ No-overwrite publication reserves the destination exclusively before replacement.
50
+ An empty reservation can briefly be visible. Python's portable APIs do not offer
51
+ an atomic conditional replace, so hostile concurrent directory/path changes or
52
+ replacement of that reservation cannot be fully guarded against. This is
53
+ best-effort race safety, not a guarantee against concurrent filesystem mutation.
54
+
55
+ ## Installation
56
+
57
+ Python 3.10 or newer is required. From a checkout of the v0.2 development branch:
58
+
59
+ ```bash
60
+ python -m pip install .
61
+ fastq-sheet-audit --version
62
+ ```
63
+
64
+ The GUI uses standard-library tkinter/ttk and needs an available Tk installation
65
+ and desktop display. Some Python distributions provide Tk separately. CLI use
66
+ does not require opening the GUI. Dependency installation may use the network;
67
+ audits and exports do not.
68
+
69
+ ## CLI quick start
70
+
71
+ Input sheets may be UTF-8 CSV or TSV, including a UTF-8 BOM, quoted fields,
72
+ LF, and CRLF. Headers, column order, cell text, and physical row numbers are
73
+ preserved. Duplicate headers after surrounding-whitespace trimming, surplus
74
+ fields, malformed quoting, and missing headers are rejected. Short rows receive
75
+ empty trailing cells; only entirely empty rows are skipped.
76
+
77
+ Example `samples.csv`:
78
+
79
+ ```csv
80
+ sample,r1,r2
81
+ A,A_S1_L001_R1_001.fastq.gz,A_S1_L001_R2_001.fastq.gz
82
+ A,A_S1_L002_R1_001.fastq.gz,A_S1_L002_R2_001.fastq.gz
83
+ ```
84
+
85
+ ```bash
86
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq
87
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq --read-mode paired --json audit.json
88
+ ```
89
+
90
+ Relative FASTQ references resolve against `--fastq-dir`, including subdirectories,
91
+ not against the sheet's directory. Absolute references remain absolute. Path
92
+ cell text is used without trimming, variable expansion, or rewriting.
93
+ Discovery recognizes `.fastq.gz`, `.fq.gz`, `.fastq`, and `.fq`, case-insensitively.
94
+ Directory symlinks are not traversed recursively; eligible file symlinks may be
95
+ inventoried.
96
+
97
+ The CLI prints a deterministic summary and ordered findings. Available options:
98
+
99
+ | Option | Meaning |
100
+ | --- | --- |
101
+ | `--read-mode {auto,paired,single}` | Requested layout; default `auto` |
102
+ | `--sample-column N` | Explicit SAMPLE column, **1-based** |
103
+ | `--r1-column N` | Explicit R1 column, **1-based** |
104
+ | `--r2-column N` | Explicit R2 column, **1-based** |
105
+ | `--no-r2-column` | Explicitly leave R2 unmapped |
106
+ | `--json PATH` | Write a structured JSON audit report |
107
+ | `--overwrite-report` | Opt in to replacement of an ordinary JSON report file |
108
+
109
+ ## Column mapping
110
+
111
+ Automatic mapping compares headers using surrounding-whitespace trimming and
112
+ Unicode casefold only. The deterministic aliases are:
113
+
114
+ | Role | Aliases |
115
+ | --- | --- |
116
+ | SAMPLE | `sample`, `sample_id`, `sampleid` |
117
+ | R1 | `r1`, `fastq_1`, `fastq1`, `read1`, `read_1` |
118
+ | R2 | `r2`, `fastq_2`, `fastq2`, `read2`, `read_2` |
119
+
120
+ SAMPLE and R1 are required; R2 is optional. Multiple candidates for any role
121
+ are refused unless explicitly resolved, including an ambiguous optional R2.
122
+ Errors list physical column numbers and exact headers. Overrides can select
123
+ non-alias headers; omitted overrides retain automatic mapping. One physical
124
+ column cannot fill multiple roles. R2 selection and unmapping are mutually
125
+ exclusive.
126
+
127
+ For a sheet with `specimen,forward,reverse`:
128
+
129
+ ```bash
130
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq --sample-column 1 --r1-column 2 --r2-column 3
131
+ ```
132
+
133
+ The GUI's **Load columns** action offers indexed choices, **Automatic**, and
134
+ **Unassigned**. Leaving SAMPLE or R1 unassigned prevents auditing. Unknown
135
+ metadata columns survive import; profile exports contain the selected profile's
136
+ columns rather than automatically copying arbitrary source metadata.
137
+
138
+ ## Read modes, pairing, and findings
139
+
140
+ | Mode | Behavior |
141
+ | --- | --- |
142
+ | `auto` | Complete biological pairs classify as paired; R1-only groups classify as single. Mixed, orphaned, ambiguous, or empty biological evidence is unresolved with a warning. |
143
+ | `paired` | Every pairable R1/R2 needs its exact mate. Missing mates and duplicate-role ambiguity are errors. |
144
+ | `single` | R1 needs no mate; biological R2 presence is reported explicitly as an error. |
145
+
146
+ Index reads, Undetermined files, and unparsed names remain visible and are
147
+ excluded from biological layout inference. The parser recognizes common forms
148
+ such as `A_R1.fastq.gz`, `A_1.fastq`, `A_S1_L001_R1_001.fastq.gz`, and
149
+ `A_I1_001.fastq.gz`; it does not claim exhaustive naming support.
150
+
151
+ Mate identity includes sample, sample number, lane, chunk, read style, suffix,
152
+ and relative parent directory. **Only sample and suffix use Unicode casefold.**
153
+ Lane/sample-number/chunk differences and R-style versus bare `1/2` remain
154
+ significant. Directory identity preserves exact spelling through a
155
+ platform-independent representation: `Run/A_R1.fastq` and `run/A_R2.fastq`
156
+ are separate identities. Files are never paired by list position or proximity.
157
+
158
+ Repeated sample IDs are allowed when rows use distinct FASTQ evidence, as in the
159
+ two-lane example. Actual file reuse, including filesystem aliases, is an error
160
+ (`FASTQ_REUSED`). Sample-versus-filename comparison trims surrounding sheet
161
+ sample whitespace and uses Unicode casefold only: `A-B` and `AB` remain distinct.
162
+ Original text is retained.
163
+
164
+ An omitted optional R2 is **not** automatically assigned. If an exact R2 exists
165
+ on disk but is absent from the sheet, it remains `UNLISTED_FASTQ` evidence.
166
+ Unknown/unparsed filenames are retained, not guessed. Filename role disagreements,
167
+ structural pair mismatches, and missing references are reported. Case-only
168
+ relative-path collisions are warnings; this is a case-portability check, not a
169
+ complete set of Windows filename rules.
170
+
171
+ ## GUI quick start and adjudication
172
+
173
+ ```bash
174
+ fastq-sheet-audit-gui
175
+ ```
176
+
177
+ Choose a FASTQ directory and sheet, load/resolve columns if needed, select a
178
+ read mode, and press **Audit**. Opening the GUI does not scan inputs automatically.
179
+ Summary, Findings, FASTQ Inventory, and Pairing / Adjudication tabs expose the
180
+ current evidence.
181
+
182
+ Select a pair row to choose R1/R2 candidates explicitly, leave a role
183
+ **Unassigned**, or **Reset automatic**. **Confirmed** records human confirmation;
184
+ it does not resolve ambiguity or override errors. Applying a decision revalidates
185
+ the workflow. All original candidates remain in the evidence even after a
186
+ selection or unassignment. Unresolved automatic choices remain unresolved.
187
+
188
+ Read-layout checks use effective adjudicated reads, while reconciliation and
189
+ case-collision checks retain raw inventory. Decisions cannot suppress unrelated
190
+ findings. The tool does not edit the source sheet to repair discrepancies;
191
+ correct it externally and rerun Audit when necessary. Changed inputs require a
192
+ new audit, and changed export options require a fresh preview.
193
+
194
+ ## Export profiles and manual metadata
195
+
196
+ GUI export requires a clean workflow, followed by a valid profile preview.
197
+ Choose a profile and path mode, set any needed manual fields per source row,
198
+ then press **Preview export**. Choose CSV or TSV and a destination explicitly
199
+ before pressing **Export**. Format is independent of filename extension.
200
+ The CLI audits and publishes JSON reports; it does not export sample sheets.
201
+
202
+ Export uses exact source sample text and effective adjudicated R1/R2 records,
203
+ not the original sheet's FASTQ path cells after adjudication. Profile columns
204
+ declare their source roles. Columns with no source role are manual:
205
+ no metadata is inferred and no descriptive profile defaults are automatically
206
+ inserted. **Set** supplies exact text, including an explicit empty string;
207
+ **Clear** makes the value absent. Unapplied editor text must be applied or
208
+ cleared before preview/export.
209
+
210
+ Validation distinguishes a required column from a required cell. String allowed
211
+ values are matched exactly without trimming or casefolding. Integer values use
212
+ an optional sign and ASCII decimal digits; text such as `01` remains unchanged
213
+ in output. Whitespace, Unicode, punctuation, and formula-like text are preserved;
214
+ CSV/TSV export is not a spreadsheet-sanitization step.
215
+
216
+ Bundled profiles are local declarative contracts, not a guarantee that every
217
+ pipeline option or future release is supported:
218
+
219
+ | Profile ID | Contract / manual fields |
220
+ | --- | --- |
221
+ | `generic` | `sample,r1`; optional `r2`. No pipeline compatibility claim. |
222
+ | `nfcore-rnaseq-3.27.0` | `sample,fastq_1,fastq_2,strandedness`. Strandedness requires an explicit exact value: `forward`, `reverse`, `unstranded`, or `auto`; no automatic default. |
223
+ | `nfcore-methylseq-4.2.0` | `sample,fastq_1,fastq_2,genome`. Genome is manual and may be empty. |
224
+ | `nfcore-smrnaseq-2.4.1` | `sample,fastq_1`; optional `fastq_2`. Profile notes say downstream small-RNA processing primarily uses R1; this tool does not silently discard R2. |
225
+ | `nfcore-viralrecon-3.0.0-illumina` | Illumina-only: `sample,fastq_1,fastq_2`. |
226
+ | `nfcore-viralrecon-3.0.0-nanopore` | Nanopore-only **barcode mapping**, `sample,barcode`; barcode is a manual integer. Metadata/editor are available, but FASTQ audit sessions cannot preview or publish this profile. Nanopore FASTQs are supplied separately by the pipeline's directory layout. |
227
+
228
+ All five FASTQ-samplesheet profiles support single-end input. For rnaseq,
229
+ methylseq, and viralrecon Illumina, `fastq_2` is a required **column** but may
230
+ contain empty cells. Generic and smrnaseq omit their optional R2 column when no
231
+ row supplies an effective R2. Methylseq's `genome` column is required but its
232
+ value is optional. Viralrecon's downstream sample-name rewriting is not
233
+ reproduced here: sample IDs are not silently renamed or normalized.
234
+
235
+ ## Export path modes
236
+
237
+ | GUI mode | Rendering |
238
+ | --- | --- |
239
+ | Local absolute | Original local absolute inventory path |
240
+ | Relative to FASTQ root | Inventory relative path in local/platform form |
241
+ | Rebased root | Relative components joined to an explicit target root |
242
+
243
+ Rebasing requires an explicit **POSIX** or **Windows** style and an absolute
244
+ root in that style. It uses pure path transformations without accessing the
245
+ target filesystem. Spaces and Unicode remain intact; unsafe relative components
246
+ are rejected rather than resolved away.
247
+
248
+ ## JSON reports and exit codes
249
+
250
+ ```bash
251
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq --json audit.json
252
+ fastq-sheet-audit check samples.csv --fastq-dir ./fastq --json audit.json --overwrite-report
253
+ ```
254
+
255
+ JSON reports use `schema_version: 1`, independently of the package version.
256
+ They preserve structured inventory, reconciliation findings and assignments,
257
+ read-mode diagnostics and evidence, case collisions, and pair candidates,
258
+ decisions, effective/unresolved records, and confirmation. Pair keys remain
259
+ structured, absent values stay null, and Unicode remains literal. Ordering is
260
+ deterministic. A report can be written even when the audit has findings;
261
+ a publication failure instead returns exit 2.
262
+
263
+ | CLI exit | Meaning |
264
+ | --- | --- |
265
+ | `0` | Audit completed with no findings |
266
+ | `1` | Audit completed with findings, including warnings or errors |
267
+ | `2` | Expected invalid input, filesystem, or report-publication failure; argparse also uses 2 for invalid command usage |
268
+
269
+ Unexpected programmer errors are not converted into ordinary audit failures.
270
+
271
+ ## Scope and development
272
+
273
+ This is a filename/path/sample-sheet preflight tool. It does not inspect read
274
+ contents, compare read counts, validate checksums, demultiplex, repair FASTQs,
275
+ run pipelines, infer biological metadata, or provide clinical validation.
276
+ Profile exports cover only the bundled declarative fields. CLI human pairing
277
+ adjudication and barcode-workflow export are outside the current scope.
278
+
279
+ ```bash
280
+ python -m pip install -e ".[dev]"
281
+ python -m pytest -q
282
+ ```
283
+
284
+ Tests are headless; they do not launch Tk. CI covers Ubuntu Python 3.10–3.14,
285
+ representative Python 3.12 jobs on Windows/macOS, and isolated sdist/wheel,
286
+ entry-point, and profile-resource validation. See [CHANGELOG.md](CHANGELOG.md)
287
+ for the v0.2.0 changes and historical 0.1.0 entry, and
288
+ [SECURITY.md](SECURITY.md) for security reporting.
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "fastq-sheet-audit"
7
+ dynamic = ["version"]
8
+ description = "Local FASTQ/sample-sheet auditing with explicit, validated sample-sheet export"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [{name = "dr-richard"}]
13
+ keywords = ["bioinformatics", "fastq", "samplesheet", "validation", "sequencing"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Operating System :: OS Independent",
17
+ ]
18
+
19
+ [project.optional-dependencies]
20
+ dev = ["pytest>=8"]
21
+
22
+ [project.scripts]
23
+ fastq-sheet-audit = "fastq_sheet_audit.cli:main"
24
+
25
+ [project.gui-scripts]
26
+ fastq-sheet-audit-gui = "fastq_sheet_audit.gui:main"
27
+
28
+ [tool.setuptools.dynamic]
29
+ version = {attr = "fastq_sheet_audit.__version__"}
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["src"]
33
+
34
+ [tool.setuptools.package-data]
35
+ "fastq_sheet_audit" = ["assets/*.png"]
36
+ "fastq_sheet_audit.profile_data" = ["*.json"]
37
+
38
+ [tool.pytest.ini_options]
39
+ pythonpath = ["src"]
40
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0"