variant-translation 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Variant Translation contributors
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,446 @@
1
+ Metadata-Version: 2.4
2
+ Name: variant-translation
3
+ Version: 0.1.0
4
+ Summary: Reverse-translate protein HGVS variants.
5
+ Author-email: Jeremy Stone <74574922+jstone-dev@users.noreply.github.com>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: click
11
+ Requires-Dist: hgvs
12
+ Requires-Dist: python-dotenv
13
+ Requires-Dist: requests
14
+ Provides-Extra: dev
15
+ Requires-Dist: black; extra == "dev"
16
+ Requires-Dist: pytest; extra == "dev"
17
+ Provides-Extra: publish
18
+ Requires-Dist: build; extra == "publish"
19
+ Requires-Dist: twine; extra == "publish"
20
+ Dynamic: license-file
21
+
22
+ # variant-translation: Tools for translating representations of genetic variants
23
+
24
+ ## Installation
25
+
26
+ ### Prerequisites
27
+
28
+ - Python 3.8 or later
29
+ - Virtual environment (recommended)
30
+
31
+ ### Option A: Install from PyPI (library + CLI)
32
+
33
+ 1. Create and activate a virtual environment:
34
+
35
+ ```bash
36
+ python -m venv .venv
37
+ source .venv/bin/activate # On macOS/Linux
38
+ # or
39
+ .venv\Scripts\activate # On Windows
40
+ ```
41
+
42
+ 2. Install from PyPI:
43
+
44
+ ```bash
45
+ pip install variant-translation
46
+ ```
47
+
48
+ 3. Run installed CLI entry points:
49
+
50
+ ```bash
51
+ reverse-translate-variants --help
52
+ compare-reverse-translated-variants --help
53
+ ```
54
+
55
+ ### Option B: Install from GitHub source
56
+
57
+ 1. Clone this repository:
58
+
59
+ ```bash
60
+ git clone git@github.com:bbi-lab/variant-translation.git
61
+ cd variant-translation
62
+ ```
63
+
64
+ 2. Create and activate a virtual environment:
65
+
66
+ ```bash
67
+ python -m venv .venv
68
+ source .venv/bin/activate # On macOS/Linux
69
+ # or
70
+ .venv\Scripts\activate # On Windows
71
+ ```
72
+
73
+ 3. Install dependencies:
74
+
75
+ ```bash
76
+ pip install -r requirements.txt
77
+ ```
78
+
79
+ 4. (Optional) Install as an editable package to use CLI entry points while developing:
80
+
81
+ ```bash
82
+ pip install -e .
83
+ ```
84
+
85
+ ## Reverse-Translate Protein Variants
86
+
87
+ ### `reverse_translate_variants.py`
88
+
89
+ Enumerate DNA variants that produce a requested protein HGVS change:
90
+
91
+ If installed from PyPI, use the `reverse-translate-variants` command in place of
92
+ `python -m src.scripts.reverse_translate_variants`.
93
+
94
+ > **Requires UTA.** This script connects to a UTA (Universal Transcript Archive) PostgreSQL database to look up
95
+ > transcript sequences and map c. variants to g. variants. See [UTA Setup](#uta-universal-transcript-archive) in
96
+ > the Configuration section.
97
+
98
+ ```bash
99
+ python -m src.scripts.reverse_translate_variants --transcript NM_000546.6 --hgvs-p p.Arg175His
100
+ ```
101
+
102
+ You can also provide a UniProt ID instead of a transcript accession. The script resolves the UniProt entry to a
103
+ MANE Select identifier before reverse translation:
104
+
105
+ ```bash
106
+ python -m src.scripts.reverse_translate_variants --uniprot-id P04637 --hgvs-p p.Arg175His
107
+ ```
108
+
109
+ By default, UniProt resolution uses `RefSeqProteinId` from
110
+ `uniProtKBCrossReferences[0].properties` and resolves it to a transcript accession. To use the MANE Select Ensembl
111
+ transcript directly (`uniProtKBCrossReferences[0].id`), set:
112
+
113
+ ```bash
114
+ python -m src.scripts.reverse_translate_variants --uniprot-id P04637 --hgvs-p p.Arg175His --uniprot-target ensembl-transcript
115
+ ```
116
+
117
+ By default, this returns all codon-local SNVs that yield the same amino-acid change, along with HGVS c. and HGVS g.
118
+ expressions.
119
+
120
+ To also consider small indels (up to 3 nt by default), including full-codon replacements
121
+ (`c.N_N+2delinsNNN`) for substitutions that are not SNV-accessible:
122
+
123
+ ```bash
124
+ python -m src.scripts.reverse_translate_variants --transcript NM_000546.6 --hgvs-p p.Arg175His --include-indels
125
+ ```
126
+
127
+ To express eligible reverse-complement replacements as HGVS inversions (`inv`) instead of `delins`:
128
+
129
+ ```bash
130
+ python -m src.scripts.reverse_translate_variants --transcript NM_000546.6 --hgvs-p p.Arg175His --include-indels --use-inv-notation
131
+ ```
132
+
133
+ To restrict premature-stop reverse translation to substitutions and same-length `delins` variants, excluding
134
+ length-changing insertion/deletion candidates:
135
+
136
+ ```bash
137
+ python -m src.scripts.reverse_translate_variants --transcript NM_000546.6 --hgvs-p p.Arg175Ter --include-indels --substitutions-and-delins-only
138
+ ```
139
+
140
+ **Key options:**
141
+ - `--assembly`: Genome assembly for HGVS g. projection (default: `GRCh38`)
142
+ - `--uniprot-id`: Resolve UniProt accession to a MANE Select identifier for single-variant mode
143
+ - `--uniprot-target`: UniProt MANE identifier source: `refseq-protein` (default) or `ensembl-transcript`
144
+ - `--include-indels`: Include codon-local insertion/deletion/delins candidates
145
+ - `--use-inv-notation`: Express eligible reverse-complement delins as HGVS `inv` variants
146
+ - `--substitutions-and-delins-only`: For premature stops, suppress length-changing insertion/deletion candidates
147
+ - `--max-indel-size`: Maximum insertion/deletion size in nucleotides (1-3)
148
+ - `--limit`: Batch mode only; process at most the first N input rows
149
+ - `--input-format`: Batch input format: `tsv` (default) or `csv`
150
+ - `--pass-through-all-columns`: Batch mode; pass through all additional non-core input columns
151
+ - `--pass-through-columns`: Batch mode; pass through specific additional column(s) (comma-separated and repeatable)
152
+ - `--pass-through-prefix`: Batch mode; prefix for passed-through additional column names
153
+ - `--one-row-per-input`: Emit exactly one output row per input row by joining multiple candidates
154
+ - `--join-delimiter`: Delimiter used with `--one-row-per-input` (default: `|`)
155
+ - `--output`: Write TSV output to a file (otherwise prints to stdout)
156
+
157
+ **Batch mode (default TSV):**
158
+
159
+ ```bash
160
+ python -m src.scripts.reverse_translate_variants --input input.tsv --output output.tsv
161
+ ```
162
+
163
+ By default, batch mode expects columns named `transcript` and `hgvs_p` (override with
164
+ `--transcript-column` and `--hgvs-p-column`). The output includes core columns (`transcript`, optional `uniprot`, and
165
+ `hgvs_p`) plus `variant_type`, `hgvs_c`, and `hgvs_g`.
166
+
167
+ Rows with missing/blank `hgvs_p` values are skipped. If one or more rows are skipped, the script emits a warning.
168
+
169
+ To pass through additional input columns, enable:
170
+
171
+ ```bash
172
+ python -m src.scripts.reverse_translate_variants --input input.tsv --pass-through-all-columns --output output.tsv
173
+ ```
174
+
175
+ To pass through only selected additional columns:
176
+
177
+ ```bash
178
+ python -m src.scripts.reverse_translate_variants \
179
+ --input input.tsv \
180
+ --pass-through-columns sample_id,project_id \
181
+ --pass-through-columns plate_id \
182
+ --output output.tsv
183
+ ```
184
+
185
+ To prefix passed-through additional column names (works with either strategy):
186
+
187
+ ```bash
188
+ python -m src.scripts.reverse_translate_variants --input input.tsv --pass-through-all-columns --pass-through-prefix input_ --output output.tsv
189
+ ```
190
+
191
+ To drive batch mode from UniProt IDs instead of transcript accessions:
192
+
193
+ ```bash
194
+ python -m src.scripts.reverse_translate_variants \
195
+ --input input.tsv \
196
+ --uniprot-column uniprot_id \
197
+ --output output.tsv
198
+ ```
199
+
200
+ To process only the first N rows in batch mode (after the header):
201
+
202
+ ```bash
203
+ python -m src.scripts.reverse_translate_variants --input input.tsv --limit 100 --output output.tsv
204
+ ```
205
+
206
+ In UniProt batch mode, the script processes input rows as a stream and resolves UniProt IDs on demand, caching
207
+ resolved transcripts so each unique ID is resolved at most once.
208
+
209
+ To output exactly one row per input row (joining multiple candidate values in each of `variant_type`, `hgvs_c`, and
210
+ `hgvs_g`):
211
+
212
+ ```bash
213
+ python -m src.scripts.reverse_translate_variants \
214
+ --input input.tsv \
215
+ --uniprot-column uniprot_id \
216
+ --hgvs-p-column hgvs_p \
217
+ --include-indels \
218
+ --one-row-per-input \
219
+ --join-delimiter "|" \
220
+ --output output_joined.tsv
221
+ ```
222
+
223
+ To use CSV input instead of TSV:
224
+
225
+ ```bash
226
+ python -m src.scripts.reverse_translate_variants --input input.csv --input-format csv --output output.tsv
227
+ ```
228
+
229
+ In this mode, the joined `hgvs_c` and `hgvs_g` lists are kept aligned so each position corresponds to the same
230
+ candidate variant.
231
+
232
+ **Auto-formatting HGVS p. strings:**
233
+
234
+ If your HGVS p. column contains one-letter amino acid notation (e.g., `A334D`, `M1V`) or single-amino-acid deletions
235
+ (e.g., `A334del`, `A334-`), use the `--auto-format-hgvs-p` flag to automatically convert these to HGVS p. format
236
+ (e.g., `p.A334D`, `p.M1V`, `p.A334del`). This applies to both single-mode and batch-mode:
237
+
238
+ ```bash
239
+ # Single mode: auto-format A334D → p.A334D before processing
240
+ python -m src.scripts.reverse_translate_variants --transcript NM_000546.6 --hgvs-p A334D --auto-format-hgvs-p
241
+
242
+ # Batch mode: auto-format one-letter notations in the hgvs_p column
243
+ python -m src.scripts.reverse_translate_variants --input input.tsv --auto-format-hgvs-p --output output.tsv
244
+ ```
245
+
246
+ Supported patterns: one-letter (e.g., `A334D`, `M1V`) and three-letter (e.g., `Ala334Asp`, `Met1Val`) amino acid
247
+ codes; single stop codon changes (e.g., `*123C`); synonymous changes (e.g., `R175=`); and deletions (e.g., `A334del`,
248
+ `A334-`, `Met1del`).
249
+
250
+ ### Compare Reverse-Translated Variant Files
251
+
252
+ Compare two single-line reverse-translation files (A and B), matching rows by exact transcript + `hgvs_p` and
253
+ reporting A-only keys, B-only keys, and rows where reverse translations differ.
254
+
255
+ If installed from PyPI, use the `compare-reverse-translated-variants` command in place of
256
+ `python -m src.scripts.compare_reverse_translated_variants`.
257
+
258
+ ```bash
259
+ python -m src.scripts.compare_reverse_translated_variants \
260
+ --a-input a.tsv \
261
+ --b-input b.tsv \
262
+ --a-only-output a_only.tsv \
263
+ --b-only-output b_only.tsv \
264
+ --different-output differences.tsv \
265
+ --a-missing-output a_missing.tsv \
266
+ --b-missing-output b_missing.tsv
267
+ ```
268
+
269
+ Key options:
270
+ - Per-file formats: `--a-input-format`, `--b-input-format` (`tsv`/`csv`)
271
+ - Per-file single-line separators: `--a-separator`, `--b-separator`
272
+ - Per-file column options: transcript, `hgvs_p`, `hgvs_c`, `hgvs_g`
273
+ - Additional key columns for matching: `--match-columns` (comma-separated and repeatable)
274
+ - Comparison scope: `--compare hgvs_c|hgvs_g|both`
275
+ - Reference-insensitive comparison: `--ignore-reference-differences`
276
+ - Differences output pass-through:
277
+ - `--pass-through-all-columns` for all non-core columns
278
+ - `--pass-through-columns` for selected non-core columns (comma-separated and repeatable)
279
+ - `--a-pass-through-prefix` and `--b-pass-through-prefix` for output naming
280
+ - Missing-key outputs: `--a-missing-output` and `--b-missing-output` for rows missing transcript or `hgvs_p`
281
+
282
+ ## Configuration
283
+
284
+ ### UTA (Universal Transcript Archive)
285
+
286
+ The `reverse_translate_variants` script depends on a UTA PostgreSQL database, which provides transcript sequences
287
+ and genomic coordinate mappings for the [biocommons `hgvs`](https://github.com/biocommons/hgvs) library. By default
288
+ the `hgvs` library connects to the public biocommons cloud instance, which can be slow or rate-limited. Running a
289
+ local Docker container is strongly recommended for any non-trivial use.
290
+
291
+ #### Step 1 — Pull and start the UTA Docker container
292
+
293
+ The `biocommons/uta` image provides a PostgreSQL instance but ships with an **empty database**. Data must be loaded
294
+ separately from a dump file (see Step 3).
295
+
296
+ ```bash
297
+ docker pull biocommons/uta:uta_20241220
298
+
299
+ docker run \
300
+ --name uta \
301
+ --platform linux/amd64 \
302
+ -e POSTGRES_PASSWORD=uta_admin \
303
+ -p 5433:5432 \
304
+ -d biocommons/uta:uta_20241220
305
+ ```
306
+
307
+ Port `5433` is used here to avoid conflicts with any other local PostgreSQL instance on the default port `5432`.
308
+ Change it to any free port you prefer.
309
+
310
+ Wait for PostgreSQL to finish initialising before proceeding. Check the logs until you see
311
+ `database system is ready to accept connections`:
312
+
313
+ ```bash
314
+ docker logs -f uta
315
+ ```
316
+
317
+ #### Step 2 — Download the UTA database dump
318
+
319
+ The dump file is available from the biocommons download server (~1–2 GB). Download it with `curl` or `wget`:
320
+
321
+ ```bash
322
+ curl -LO "http://dl.biocommons.org/uta/uta_20241220.pgd.gz"
323
+ ```
324
+
325
+ If the download fails or is very slow, you can also find the file on the
326
+ [biocommons/uta GitHub releases page](https://github.com/biocommons/uta/releases).
327
+
328
+ #### Step 3 — Restore the dump into the container
329
+
330
+ The dump is a gzip-compressed plain-SQL file. Pipe it directly into the running container:
331
+
332
+ ```bash
333
+ gzip -cdq uta_20241220.pgd.gz | docker exec -i uta psql -U uta_admin uta
334
+ ```
335
+
336
+ This will take several minutes to complete. There is no progress indicator; the shell prompt will return when the
337
+ restore is done.
338
+
339
+ #### Step 4 — Set the UTA_DB_URL environment variable
340
+
341
+ Tell the `hgvs` library (and therefore this script) where to find the local instance:
342
+
343
+ ```bash
344
+ export UTA_DB_URL="postgresql://anonymous@localhost:5433/uta/uta_20241220"
345
+ ```
346
+
347
+ You can add this line to your shell profile or `.env` file so it persists across sessions.
348
+
349
+ If `UTA_DB_URL` is not set the library falls back to the public cloud instance at
350
+ `postgresql://anonymous:anonymous@uta.biocommons.org/uta/uta_20241220`.
351
+
352
+ #### Stop, restart, and remove the container
353
+
354
+ ```bash
355
+ docker stop uta
356
+ docker start uta # reuses the existing container; no need to restore again
357
+ ```
358
+
359
+ To remove the container entirely (data will be lost; restore step must be repeated):
360
+
361
+ ```bash
362
+ docker rm -f uta
363
+ ```
364
+
365
+ #### Verify the connection
366
+
367
+ ```bash
368
+ psql "postgresql://anonymous@localhost:5433/uta" -c "SELECT count(*) FROM uta_20241220.tx_exon_aln_v LIMIT 1;"
369
+ ```
370
+
371
+ A row count result confirms the database is accessible and the schema is populated.
372
+
373
+ ## Dependencies
374
+
375
+ Key dependencies include:
376
+
377
+ - **click**: Command-line interface creation
378
+ - **hgvs**: HGVS variant parsing and validation
379
+
380
+ See [requirements.txt](requirements.txt) for the complete list.
381
+
382
+ ## Publish to PyPI
383
+
384
+ From a clean, version-tagged working tree:
385
+
386
+ Before building, bump `version` in `pyproject.toml`.
387
+
388
+ ### Release checklist
389
+
390
+ - [ ] Bump `version` in `pyproject.toml`.
391
+ - [ ] Ensure tests pass (`pytest`).
392
+ - [ ] Rebuild distributions from a clean state (`rm -rf dist build *.egg-info`).
393
+ - [ ] Build artifacts (`python -m build`).
394
+ - [ ] Validate metadata (`python -m twine check dist/*`).
395
+ - [ ] (Recommended) Upload and test install via TestPyPI.
396
+ - [ ] Upload to PyPI (`python -m twine upload dist/*`).
397
+
398
+ ### One-command release targets
399
+
400
+ This repository includes a `Makefile` with release targets that implement the checklist steps:
401
+
402
+ ```bash
403
+ make release-prep # test + clean + build + twine check
404
+ make release-testpypi # release-prep + upload to TestPyPI
405
+ make release # release-prep + upload to PyPI
406
+ ```
407
+
408
+ 1. Install publishing dependencies:
409
+
410
+ ```bash
411
+ pip install .[publish]
412
+ ```
413
+
414
+ 2. Build source and wheel distributions:
415
+
416
+ ```bash
417
+ python -m build
418
+ ```
419
+
420
+ 3. Validate distribution metadata:
421
+
422
+ ```bash
423
+ python -m twine check dist/*
424
+ ```
425
+
426
+ 4. Upload to PyPI:
427
+
428
+ ```bash
429
+ python -m twine upload dist/*
430
+ ```
431
+
432
+ ### TestPyPI dry-run (recommended before production upload)
433
+
434
+ Use TestPyPI to validate packaging and installation without publishing to the main index:
435
+
436
+ 1. Upload to TestPyPI:
437
+
438
+ ```bash
439
+ python -m twine upload --repository testpypi dist/*
440
+ ```
441
+
442
+ 2. Install from TestPyPI in a clean virtual environment:
443
+
444
+ ```bash
445
+ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple variant-translation
446
+ ```