samplesheet-parser 0.1.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 (30) hide show
  1. samplesheet_parser-0.1.0/.github/workflows/ci.yml +64 -0
  2. samplesheet_parser-0.1.0/.gitignore +40 -0
  3. samplesheet_parser-0.1.0/LICENSE +19 -0
  4. samplesheet_parser-0.1.0/PKG-INFO +384 -0
  5. samplesheet_parser-0.1.0/README.md +334 -0
  6. samplesheet_parser-0.1.0/examples/parse_examples.py +114 -0
  7. samplesheet_parser-0.1.0/examples/sample_sheets/README.md +92 -0
  8. samplesheet_parser-0.1.0/examples/sample_sheets/v1_dual_index.csv +27 -0
  9. samplesheet_parser-0.1.0/examples/sample_sheets/v1_multi_lane.csv +31 -0
  10. samplesheet_parser-0.1.0/examples/sample_sheets/v1_single_index.csv +25 -0
  11. samplesheet_parser-0.1.0/examples/sample_sheets/v2_nextseq_single_index.csv +25 -0
  12. samplesheet_parser-0.1.0/examples/sample_sheets/v2_novaseq_x_dual_index.csv +24 -0
  13. samplesheet_parser-0.1.0/examples/sample_sheets/v2_with_index_umi.csv +28 -0
  14. samplesheet_parser-0.1.0/examples/sample_sheets/v2_with_read_umi.csv +24 -0
  15. samplesheet_parser-0.1.0/pyproject.toml +73 -0
  16. samplesheet_parser-0.1.0/samplesheet_parser/__init__.py +50 -0
  17. samplesheet_parser-0.1.0/samplesheet_parser/enums.py +54 -0
  18. samplesheet_parser-0.1.0/samplesheet_parser/factory.py +240 -0
  19. samplesheet_parser-0.1.0/samplesheet_parser/parsers/__init__.py +6 -0
  20. samplesheet_parser-0.1.0/samplesheet_parser/parsers/v1.py +536 -0
  21. samplesheet_parser-0.1.0/samplesheet_parser/parsers/v2.py +622 -0
  22. samplesheet_parser-0.1.0/samplesheet_parser/validators.py +323 -0
  23. samplesheet_parser-0.1.0/tests/__init__.py +0 -0
  24. samplesheet_parser-0.1.0/tests/conftest.py +291 -0
  25. samplesheet_parser-0.1.0/tests/test_factory.py +106 -0
  26. samplesheet_parser-0.1.0/tests/test_parsers/__init__.py +0 -0
  27. samplesheet_parser-0.1.0/tests/test_parsers/test_v1.py +236 -0
  28. samplesheet_parser-0.1.0/tests/test_parsers/test_v2.py +183 -0
  29. samplesheet_parser-0.1.0/tests/test_validators/__init__.py +0 -0
  30. samplesheet_parser-0.1.0/tests/test_validators/test_validators.py +205 -0
@@ -0,0 +1,64 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install dependencies
25
+ run: pip install -e ".[dev]"
26
+
27
+ - name: Lint with ruff
28
+ run: ruff check samplesheet_parser/
29
+
30
+ - name: Type check with mypy
31
+ run: mypy samplesheet_parser/ --ignore-missing-imports
32
+ continue-on-error: true
33
+
34
+ - name: Run tests
35
+ run: pytest tests/ -v --cov=samplesheet_parser --cov-report=xml
36
+
37
+ - name: Upload coverage to Codecov
38
+ uses: codecov/codecov-action@v4
39
+ if: matrix.python-version == '3.12'
40
+ with:
41
+ file: ./coverage.xml
42
+
43
+ publish:
44
+ needs: test
45
+ runs-on: ubuntu-latest
46
+ if: startsWith(github.ref, 'refs/tags/v')
47
+ permissions:
48
+ id-token: write
49
+
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+
53
+ - name: Set up Python
54
+ uses: actions/setup-python@v5
55
+ with:
56
+ python-version: "3.12"
57
+
58
+ - name: Build package
59
+ run: |
60
+ pip install hatchling
61
+ python -m hatchling build
62
+
63
+ - name: Publish to PyPI
64
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,40 @@
1
+ BLOGPOST.md
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+ .Python
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+ .eggs/
11
+ *.egg
12
+
13
+ # Testing
14
+ .pytest_cache/
15
+ .coverage
16
+ coverage.xml
17
+ htmlcov/
18
+ .tox/
19
+
20
+ # Type checking
21
+ .mypy_cache/
22
+
23
+ # Virtual environments
24
+ .venv/
25
+ venv/
26
+ env/
27
+
28
+ # Editor
29
+ .vscode/
30
+ .idea/
31
+ *.swp
32
+ *.swo
33
+
34
+ # macOS
35
+ .DS_Store
36
+
37
+ # Backup files created by parser cleaning
38
+ *.backup
39
+ *.tmp
40
+
@@ -0,0 +1,19 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ Copyright 2026 Chaitanya Kasaraneni
8
+
9
+ Licensed under the Apache License, Version 2.0 (the "License");
10
+ you may not use this file except in compliance with the License.
11
+ You may obtain a copy of the License at
12
+
13
+ http://www.apache.org/licenses/LICENSE-2.0
14
+
15
+ Unless required by applicable law or agreed to in writing, software
16
+ distributed under the License is distributed on an "AS IS" BASIS,
17
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ See the License for the specific language governing permissions and
19
+ limitations under the License.
@@ -0,0 +1,384 @@
1
+ Metadata-Version: 2.4
2
+ Name: samplesheet-parser
3
+ Version: 0.1.0
4
+ Summary: Format-agnostic parser for Illumina SampleSheet.csv files — supports IEM V1 and BCLConvert V2
5
+ Project-URL: Homepage, https://github.com/chaitanyakasaraneni/samplesheet-parser
6
+ Project-URL: Documentation, https://illumina-samplesheet.readthedocs.io
7
+ Project-URL: Repository, https://github.com/chaitanyakasaraneni/samplesheet-parser
8
+ Project-URL: Issues, https://github.com/chaitanyakasaraneni/samplesheet-parser/issues
9
+ Author-email: Chaitanya Kasaraneni <kc.kasaraneni@gmail.com>
10
+ License: Apache License
11
+ Version 2.0, January 2004
12
+ http://www.apache.org/licenses/
13
+
14
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
15
+
16
+ Copyright 2026 Chaitanya Kasaraneni
17
+
18
+ Licensed under the Apache License, Version 2.0 (the "License");
19
+ you may not use this file except in compliance with the License.
20
+ You may obtain a copy of the License at
21
+
22
+ http://www.apache.org/licenses/LICENSE-2.0
23
+
24
+ Unless required by applicable law or agreed to in writing, software
25
+ distributed under the License is distributed on an "AS IS" BASIS,
26
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27
+ See the License for the specific language governing permissions and
28
+ limitations under the License.
29
+ License-File: LICENSE
30
+ Keywords: bcl2fastq,bclconvert,bioinformatics,demultiplexing,genomics,illumina,ngs,samplesheet,sequencing
31
+ Classifier: Development Status :: 3 - Alpha
32
+ Classifier: Intended Audience :: Developers
33
+ Classifier: Intended Audience :: Science/Research
34
+ Classifier: License :: OSI Approved :: Apache Software License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.10
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
40
+ Classifier: Typing :: Typed
41
+ Requires-Python: >=3.10
42
+ Requires-Dist: loguru>=0.7
43
+ Provides-Extra: dev
44
+ Requires-Dist: black>=24.0; extra == 'dev'
45
+ Requires-Dist: mypy>=1.8; extra == 'dev'
46
+ Requires-Dist: pytest-cov>=4.1; extra == 'dev'
47
+ Requires-Dist: pytest>=7.4; extra == 'dev'
48
+ Requires-Dist: ruff>=0.3; extra == 'dev'
49
+ Description-Content-Type: text/markdown
50
+
51
+ # samplesheet-parser
52
+
53
+ **Format-agnostic Python parser for Illumina `SampleSheet.csv` files.**
54
+
55
+ Supports IEM V1 (bcl2fastq / NovaSeq 6000 era) and BCLConvert V2 (NovaSeq X series) with automatic format detection, index validation, and `OverrideCycles` / UMI decoding — no format hints required from the caller.
56
+
57
+ [![PyPI version](https://badge.fury.io/py/samplesheet-parser.svg)](https://badge.fury.io/py/samplesheet-parser)
58
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
59
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-yellow.svg)](https://opensource.org/licenses/Apache-2.0)
60
+ [![Tests](https://github.com/chaitanyakasaraneni/samplesheet-parser/actions/workflows/ci.yml/badge.svg)](https://github.com/chaitanyakasaraneni/samplesheet-parser/actions)
61
+ [![codecov](https://codecov.io/gh/chaitanyakasaraneni/samplesheet-parser/branch/main/graph/badge.svg)](https://codecov.io/gh/chaitanyakasaraneni/samplesheet-parser)
62
+
63
+ ---
64
+
65
+ ## The problem
66
+
67
+ Labs running mixed instrument fleets — NovaSeq 6000 alongside NovaSeq X series — produce two structurally incompatible `SampleSheet.csv` formats:
68
+
69
+ | | IEM V1 | BCLConvert V2 |
70
+ |---|---|---|
71
+ | Discriminator | `IEMFileVersion` in `[Header]` | `FileFormatVersion` in `[Header]` |
72
+ | Data section | `[Data]` | `[BCLConvert_Data]` |
73
+ | Settings section | `[Settings]` | `[BCLConvert_Settings]` |
74
+ | Index columns | `index`, `index2` (lowercase) | `Index`, `Index2` (uppercase) |
75
+ | Read cycles | Bare integers | Key-value (`Read1Cycles,151`) |
76
+ | UMI encoding | Not supported | `OverrideCycles` string |
77
+ | Used with | bcl2fastq | BCLConvert ≥ 3.x |
78
+
79
+ Without a single parser, every pipeline component that reads a SampleSheet needs an `if v1 else v2` branch — or worse, the format is hardcoded and the wrong sheet is silently processed.
80
+
81
+ ---
82
+
83
+ ## Installation
84
+
85
+ ```bash
86
+ pip install samplesheet-parser
87
+ ```
88
+
89
+ Requires Python 3.10+. The only mandatory dependency is [`loguru`](https://github.com/Delgan/loguru).
90
+
91
+ ---
92
+
93
+ ## Quickstart
94
+
95
+ ### Auto-detect format (recommended)
96
+
97
+ ```python
98
+ from samplesheet_parser import SampleSheetFactory
99
+
100
+ factory = SampleSheetFactory()
101
+ sheet = factory.create_parser("SampleSheet.csv", parse=True)
102
+
103
+ print(factory.version) # SampleSheetVersion.V1 or .V2
104
+ print(sheet.index_type()) # "dual", "single", or "none"
105
+ print(factory.get_umi_length()) # 0 if no UMI
106
+
107
+ for sample in sheet.samples():
108
+ print(sample["sample_id"], sample["index"])
109
+ ```
110
+
111
+ ### Validate before demultiplexing
112
+
113
+ ```python
114
+ from samplesheet_parser import SampleSheetFactory, SampleSheetValidator
115
+
116
+ sheet = SampleSheetFactory().create_parser("SampleSheet.csv", parse=True)
117
+ result = SampleSheetValidator().validate(sheet)
118
+
119
+ print(result.summary())
120
+ # PASS — 0 error(s), 1 warning(s)
121
+
122
+ for err in result.errors:
123
+ print(err)
124
+ # [ERROR] DUPLICATE_INDEX: Index 'ATTACTCG+TATAGCCT' appears more than once in lane 1.
125
+ ```
126
+
127
+ ### UMI extraction (V2 only)
128
+
129
+ ```python
130
+ from samplesheet_parser import SampleSheetV2
131
+
132
+ sheet = SampleSheetV2("SampleSheet.csv", parse=True)
133
+
134
+ # OverrideCycles: Y151;I10U9;I10;Y151 → 9 bp UMI in Index1
135
+ print(sheet.get_umi_length()) # 9
136
+ rs = sheet.get_read_structure()
137
+ print(rs.umi_location) # "index2"
138
+ print(rs.read_structure) # {"read1_template": 151, "index2_length": 10, "index2_umi": 9, ...}
139
+ ```
140
+
141
+ ### Use parsers directly
142
+
143
+ ```python
144
+ from samplesheet_parser import SampleSheetV1, SampleSheetV2
145
+
146
+ # V1
147
+ v1 = SampleSheetV1("SampleSheet_v1.csv", parse=True)
148
+ print(v1.experiment_name) # "240115_A01234_0042_AHJLG7DRXX"
149
+ print(v1.instrument_type) # "NovaSeq 6000"
150
+ print(v1.adapter_read1) # "AGATCGGAAGAGCACACGTCTGAACTCCAGTCA"
151
+ print(v1.adapter_read2) # "AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT"
152
+ print(v1.reverse_complement) # 0
153
+ print(v1.read_lengths) # [151, 151]
154
+
155
+ # V2
156
+ v2 = SampleSheetV2("SampleSheet_v2.csv", parse=True)
157
+ print(v2.instrument_platform) # "NovaSeqXSeries"
158
+ print(v2.software_version) # "3.9.3"
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Format detection logic
164
+
165
+ The factory uses a three-step strategy — stopping as early as possible:
166
+
167
+ ```
168
+ 1. Scan [Header] for FileFormatVersion → V2
169
+ or IEMFileVersion → V1
170
+
171
+ 2. If undetermined: scan full file for
172
+ [BCLConvert_Settings] or
173
+ [BCLConvert_Data] → V2
174
+
175
+ 3. Default → V1
176
+ ```
177
+
178
+ The file is read only once. No second `open()`, no `seek()`.
179
+
180
+ ---
181
+
182
+ ## OverrideCycles decoding
183
+
184
+ The V2 `OverrideCycles` string encodes the full read structure using single-letter type codes:
185
+
186
+ | Code | Meaning |
187
+ |---|---|
188
+ | `Y` | Template (sequenced) bases |
189
+ | `I` | Index bases |
190
+ | `U` | UMI bases |
191
+ | `N` | Masked / skipped bases |
192
+
193
+ Segment order: `Read1 ; Index1 ; Index2 ; Read2`
194
+
195
+ | OverrideCycles | UMI length | UMI location |
196
+ |---|---|---|
197
+ | `Y151;I10;I10;Y151` | 0 | — |
198
+ | `Y151;I10U9;I10;Y151` | 9 bp | Index1 |
199
+ | `U5Y146;I8;I8;U5Y146` | 5 bp | Read1 + Read2 |
200
+ | `Y76;I8;Y76` | 0 | — (single-index) |
201
+
202
+ ---
203
+
204
+ ## Validation checks
205
+
206
+ | Code | Level | Condition |
207
+ |---|---|---|
208
+ | `EMPTY_SAMPLES` | error | No samples found in data section |
209
+ | `INVALID_INDEX_CHARS` | error | Index contains non-ACGTN characters |
210
+ | `INDEX_TOO_LONG` | error | Index longer than 24 bp |
211
+ | `DUPLICATE_INDEX` | error | Two samples share an index in the same lane |
212
+ | `DUPLICATE_SAMPLE_ID` | error | Same `Sample_ID` appears twice in one lane |
213
+ | `INDEX_TOO_SHORT` | warning | Index shorter than 6 bp |
214
+ | `NO_ADAPTERS` | warning | No adapter sequences configured |
215
+ | `ADAPTER_MISMATCH` | warning | Adapter is not a standard Illumina sequence |
216
+
217
+ ---
218
+
219
+ ## API reference
220
+
221
+ ### `SampleSheetFactory`
222
+
223
+ ```python
224
+ factory = SampleSheetFactory()
225
+ sheet = factory.create_parser(path, *, clean=True, experiment_id=None, parse=None)
226
+ ```
227
+
228
+ | Attribute / Method | Returns | Description |
229
+ |---|---|---|
230
+ | `.create_parser(path, ...)` | `SampleSheetV1 \| SampleSheetV2` | Auto-detect format and return parser |
231
+ | `.get_umi_length()` | `int` | UMI length from current parser |
232
+ | `.version` | `SampleSheetVersion` | Detected version after `create_parser()` |
233
+
234
+ ### Shared interface — `SampleSheetV1` and `SampleSheetV2`
235
+
236
+ | Method / Attribute | Returns | Description |
237
+ |---|---|---|
238
+ | `.parse(do_clean=True)` | `None` | Parse all sections |
239
+ | `.samples()` | `list[dict]` | One record per unique sample |
240
+ | `.index_type()` | `str` | `"dual"`, `"single"`, or `"none"` |
241
+ | `.adapters` | `list[str]` | All configured adapter sequences |
242
+ | `.experiment_name` | `str \| None` | Run or experiment name |
243
+ | `.read_lengths` / `.reads` | `list[int]` / `dict` | Read cycle lengths |
244
+
245
+ ### V1-specific
246
+
247
+ | Attribute | Type | Description |
248
+ |---|---|---|
249
+ | `.iem_version` | `str \| None` | e.g. `"5"` |
250
+ | `.instrument_type` | `str \| None` | e.g. `"NovaSeq 6000"`, `"MiSeq"` |
251
+ | `.application` | `str \| None` | e.g. `"FASTQ Only"` |
252
+ | `.assay` | `str \| None` | Library prep kit name |
253
+ | `.index_adapters` | `str \| None` | Illumina index set name |
254
+ | `.chemistry` | `str \| None` | `"Amplicon"` = dual index, `"Default"` = single/no index |
255
+ | `.adapter_read1` | `str` | Read 1 adapter (`Adapter` or `AdapterRead1` key) |
256
+ | `.adapter_read2` | `str` | Read 2 adapter (`AdapterRead2` key) |
257
+ | `.reverse_complement` | `int` | `0` = default, `1` = reverse-complement R2 (Nextera MP only) |
258
+ | `.flowcell_id` | `str \| None` | Parsed from experiment ID run folder name |
259
+
260
+ ### V2-specific
261
+
262
+ | Method / Attribute | Returns | Description |
263
+ |---|---|---|
264
+ | `.get_umi_length()` | `int` | UMI length from `OverrideCycles` |
265
+ | `.get_read_structure()` | `ReadStructure` | Full decoded read structure |
266
+ | `.instrument_platform` | `str \| None` | e.g. `"NovaSeqXSeries"` |
267
+ | `.software_version` | `str \| None` | BCLConvert version string |
268
+ | `.custom_fields` | `dict[str, set[str]]` | Non-standard fields by section |
269
+
270
+ ---
271
+
272
+ ## Example sample sheets
273
+
274
+ The [`examples/sample_sheets/`](examples/sample_sheets/) directory contains ready-to-use reference sheets for every supported configuration:
275
+
276
+ | File | Format | Instrument | UMI | Use case |
277
+ |---|---|---|---|---|
278
+ | `v1_dual_index.csv` | V1 | NovaSeq 6000 | No | Standard WGS, multi-lane |
279
+ | `v1_single_index.csv` | V1 | NextSeq 500 | No | Small RNA |
280
+ | `v1_multi_lane.csv` | V1 | NovaSeq 6000 | No | 4 lanes, mixed projects |
281
+ | `v2_novaseq_x_dual_index.csv` | V2 | NovaSeq X | No | Standard PE150 |
282
+ | `v2_with_index_umi.csv` | V2 | NovaSeq X | Index1 UMI (9 bp) | cfDNA / liquid biopsy |
283
+ | `v2_with_read_umi.csv` | V2 | NovaSeq X | Read UMI (5 bp) | Duplex sequencing |
284
+ | `v2_nextseq_single_index.csv` | V2 | NextSeq 1000/2000 | No | Amplicon panel |
285
+
286
+ Run the demo to parse all of them:
287
+
288
+ ```bash
289
+ python examples/parse_examples.py
290
+ ```
291
+
292
+ ---
293
+
294
+ ## V1 adapter key reference
295
+
296
+ From the [Illumina IEM specification](https://knowledge.illumina.com/software/on-premises-software/software-on-premises-software-reference_material-list/000002204), the correct V1 `[Settings]` adapter keys are:
297
+
298
+ ```csv
299
+ [Settings]
300
+ ReverseComplement,0
301
+ Adapter,AGATCGGAAGAGCACACGTCTGAACTCCAGTCA
302
+ AdapterRead2,AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT
303
+ ```
304
+
305
+ - `Adapter` = Read 1 adapter (primary key per IEM spec)
306
+ - `AdapterRead2` = Read 2 adapter (explicit separate key)
307
+ - `AdapterRead1` = BCLConvert V1-mode alias for `Adapter` (also accepted)
308
+ - `ReverseComplement,1` = only for Nextera Mate Pair libraries; `0` for everything else
309
+
310
+ ---
311
+
312
+ ## Project structure
313
+
314
+ ```
315
+ samplesheet-parser/
316
+ ├── samplesheet_parser/
317
+ │ ├── __init__.py # Public API
318
+ │ ├── factory.py # SampleSheetFactory — auto-detection
319
+ │ ├── enums.py # SampleSheetVersion, IndexType, ...
320
+ │ ├── validators.py # SampleSheetValidator, ValidationResult
321
+ │ └── parsers/
322
+ │ ├── v1.py # IEM V1 parser (bcl2fastq)
323
+ │ └── v2.py # BCLConvert V2 parser (NovaSeq X)
324
+ ├── tests/
325
+ │ ├── conftest.py # Shared fixtures
326
+ │ ├── test_factory.py
327
+ │ ├── test_parsers/
328
+ │ │ ├── test_v1.py
329
+ │ │ └── test_v2.py
330
+ │ └── test_validators/
331
+ │ └── test_validators.py
332
+ ├── examples/
333
+ │ ├── parse_examples.py # Demo script
334
+ │ └── sample_sheets/ # Reference SampleSheet.csv files
335
+ ├── pyproject.toml
336
+ ├── LICENSE
337
+ └── README.md
338
+ ```
339
+
340
+ ---
341
+
342
+ ## Development
343
+
344
+ ```bash
345
+ git clone https://github.com/chaitanyakasaraneni/samplesheet-parser
346
+ cd samplesheet-parser
347
+ pip install -e ".[dev]"
348
+
349
+ # Run tests
350
+ pytest tests/ -v
351
+
352
+ # Run example demo
353
+ python examples/parse_examples.py
354
+ ```
355
+
356
+ ---
357
+
358
+ ## Citation
359
+
360
+ If you use this library in a published pipeline or analysis, please cite:
361
+
362
+ ```bibtex
363
+ @software{kasaraneni2026samplsheetparser,
364
+ author = {Kasaraneni, Chaitanya},
365
+ title = {samplesheet-parser: Format-agnostic parser for Illumina SampleSheet.csv},
366
+ year = {2026},
367
+ url = {https://github.com/chaitanyakasaraneni/samplesheet-parser},
368
+ version = {0.1.0}
369
+ }
370
+ ```
371
+
372
+ ---
373
+
374
+ ## License
375
+
376
+ Apache 2.0 — see [LICENSE](LICENSE).
377
+
378
+ ---
379
+
380
+ ## Related resources
381
+
382
+ - [Illumina IEM V1 SampleSheet reference (Knowledge Article #2204)](https://knowledge.illumina.com/software/on-premises-software/software-on-premises-software-reference_material-list/000002204)
383
+ - [BCLConvert Software Guide](https://support.illumina.com/sequencing/sequencing_software/bcl-convert.html)
384
+ - [Upgrading from bcl2fastq to BCLConvert](https://knowledge.illumina.com/software/general/software-general-reference_material-list/000003710)