telometer 2.0.2__tar.gz → 2.0.3__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.
@@ -1,4 +1,6 @@
1
- Copyright (c) 2024 The Python Packaging Authority
1
+ MIT License
2
+
3
+ Copyright (c) 2023 santiago-es
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,155 @@
1
+ Metadata-Version: 2.1
2
+ Name: telometer
3
+ Version: 2.0.3
4
+ Summary: Quantitative digital telomere measurement from nanopore long reads
5
+ Author-email: "Santiago E. Sanchez" <santy.esanchez@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2023 santiago-es
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Classifier: Development Status :: 4 - Beta
29
+ Classifier: Intended Audience :: Science/Research
30
+ Classifier: License :: OSI Approved :: MIT License
31
+ Classifier: Operating System :: OS Independent
32
+ Classifier: Programming Language :: Python :: 3
33
+ Classifier: Programming Language :: Python :: 3.8
34
+ Classifier: Programming Language :: Python :: 3.9
35
+ Classifier: Programming Language :: Python :: 3.10
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
39
+ Requires-Python: >=3.8
40
+ Description-Content-Type: text/markdown
41
+ License-File: LICENSE.txt
42
+ Requires-Dist: numpy
43
+ Requires-Dist: pandas
44
+ Requires-Dist: pysam
45
+ Requires-Dist: regex
46
+ Requires-Dist: scipy
47
+
48
+ # Telometer 2.0.3
49
+
50
+ A tool for measuring chromosome-specific telomeres from long-read alignments.
51
+
52
+ [Telometer Github](https://github.com/santiago-es/Telometer)
53
+
54
+ Version 2.0.3 simplifies the main variant-output table and adds individual tract lengths and a fractional first-tract position. Telomere measurement, alignment selection, variant-tract qualification, and enrichment accounting are unchanged from the uploaded 2.0.2 baseline.
55
+
56
+ ## Install and run
57
+
58
+ The distribution retains its Python **>=3.8** declaration and unpinned numpy, pandas, pysam, regex, and scipy dependencies. Validation for this revision uses **Python 3.11.13**; this does not establish compatibility with older interpreters or every platform/dependency combination. The standalone bundle includes the previously tested dependency pins in `requirements.txt`.
59
+
60
+ In an activated Python environment, install a downloaded release file:
61
+
62
+ ```bash
63
+ uv pip install ./telometer-2.0.3-py3-none-any.whl
64
+ # Or build/install the source distribution:
65
+ uv pip install ./telometer-2.0.3.tar.gz
66
+
67
+ telometer --version
68
+ ```
69
+
70
+ The version command prints `Telometer v2.0.3`. Run on a sorted BAM aligned to a confirmed compatible reference:
71
+
72
+ ```bash
73
+ # WGS; use -m 1000 for telomere capture libraries.
74
+ telometer -b sample.sorted.bam -o telomeres.tsv -m 4000 -g 20 -t 2 -l 1
75
+
76
+ # Optional variant motif and independently optional enrichment:
77
+ telometer -b sample.sorted.bam -o telomeres_variants.tsv -m 4000 -g 20 -t 2 -l 1 \
78
+ --variant-motif TGCGGT --min-variant-units 2 -e
79
+ ```
80
+
81
+ `TGCGGT` is an example, not an inferred or default motif. Both optional features are off unless requested. `-e` / `--enrichment` is a Boolean switch with no value. The existing minimum-length default is 1000 bp; the gap default is 20. `-l` is a nominal batch-size setting in GiB, **not a total-memory limit**. With enrichment enabled, memory also scales with the number of unique read IDs. Choose resources using a representative subset.
82
+
83
+ The console entry point is `telometer.telometer:run_telometer`. Package-context alternatives are `python -m telometer.telometer` and `from telometer.telometer import process_bam_file`. There is no `python -m telometer` launcher or root-level function re-export in this package.
84
+
85
+ For the standalone ZIP, extract **all five files together**, install its requirements, and invoke `python telometer.py`. Its two helper modules must remain adjacent to the caller. The separate drop-in package module uses relative imports and is not a self-contained standalone script.
86
+
87
+ ## Main TSV
88
+
89
+ With variant mode and enrichment both enabled, columns are exactly:
90
+
91
+ ```text
92
+ chromosome
93
+ reference_start
94
+ reference_end
95
+ telomere_length
96
+ read_id
97
+ mapping_quality
98
+ read_length
99
+ arm
100
+ direction
101
+ variant_motif
102
+ variant_present
103
+ variant_tract_count
104
+ pre_variant_bp
105
+ telomeres_per_gb
106
+ variant_tract_lengths
107
+ percent_pre_variant
108
+ ```
109
+
110
+ Without `-e`, `telomeres_per_gb` is omitted. Without variant mode, all variant-specific columns are omitted. The four mode widths are **9 / 10 / 15 / 16** for neither / enrichment only / variants only / both. Empty tables retain the appropriate headers. Missing values in the main TSV are the literal **`NA`**; genuine zeros are preserved. Main row order may vary across worker runs, so compare by read ID.
111
+
112
+ ### Individual tract lengths
113
+
114
+ `variant_tract_lengths` contains integer base-pair spans, separated by commas without spaces, in the existing companion `tract_id` order (increasing original-read query coordinates). There is one entry per qualifying tract. These are spans, not six-base repeat counts or merged/union coverage. Separately counted overlapping tracts remain separate, and lengths are not rounded to multiples of six. Reads without qualifying tracts have `NA`.
115
+
116
+ ### Fractional first-tract position
117
+
118
+ `percent_pre_variant` is a **0–1 fraction**, not a 0–100 percentage. It describes the first qualifying tract's position from the called telomere's subtelomeric-facing end toward its distal end. In the existing original-orientation coordinate frame, let `T0` and `T1` be the selected telomere boundaries:
119
+
120
+ - Right-terminal telomere: `(minimum tract start - T0) / telomere_length`.
121
+ - Left-terminal telomere: `(T1 - maximum tract end) / telomere_length`.
122
+
123
+ The coordinate frame includes consistent recorded hard-clip offsets. No qualifying tract or an ambiguous/unidentifiable terminal side gives `NA`. A tract at the proximal boundary gives a genuine zero. The lengths list stays in query-coordinate order even when the proximal-first tract is its last entry.
124
+
125
+ Unlike the unchanged `pre_variant_bp`, the new fraction **does not require a supported alignment/repeat-free-flank anchor**. It can therefore be numeric when `pre_variant_bp` is `NA`. It measures position within the called telomere interval, not a verified physical subtelomeric junction or historical telomere length. Detection and tract-support thresholds are unchanged.
126
+
127
+ ## Companion table and enrichment
128
+
129
+ Variant mode still writes `<output_stem>_variant_tracts.tsv` with its unchanged 20-column schema, per-tract values, and missing-value formatting. The eight removed main-table coverage/diagnostic fields are not used to change calls or suppress internal diagnostics. Use a fresh output stem to avoid confusing an old companion with a new variant-disabled run.
130
+
131
+ Enrichment remains:
132
+
133
+ `final measured unique read-ID count * 1,000,000,000 / nonredundant recorded read bases in the BAM`
134
+
135
+ Each QNAME contributes one consistent recorded full length before filtering; repeated alignments do not multiply bases. Query-consuming CIGAR operations and recorded hard clips determine full length when available. Unresolved/conflicting lengths, unusable IDs, or paired-end input can make the aggregate unavailable; valid measurements are still written with `NA` enrichment. Positive recorded bases with zero calls give rate zero; an empty/zero-base BAM has unavailable rate. The sample-wide value is repeated on measured rows, not calculated independently per read. Preserve the console log for sample totals when the output has no rows.
136
+
137
+ The BAM cannot recover reads removed upstream or trimming that is absent from its metadata. This rate is not necessarily total instrument yield or a fold-enrichment comparison. Software regression checks are not independent biological validation of variant status, telomere boundaries, or positional interpretation.
138
+
139
+ ## Build and manual publication
140
+
141
+ The supplied flat layout and `setuptools>=61,<76` backend policy are retained. Build in an activated environment:
142
+
143
+ ```bash
144
+ uv pip install "build==1.5.0"
145
+ python -m build
146
+ ```
147
+
148
+ Use current Twine and packaging when checking metadata:
149
+
150
+ ```bash
151
+ uv pip install --upgrade "twine>=6.1.0" "packaging>=24.2"
152
+ python -m twine check --strict dist/telometer-2.0.3-py3-none-any.whl dist/telometer-2.0.3.tar.gz
153
+ ```
154
+
155
+ Publishing is a separate maintainer action; these files do not update GitHub or PyPI automatically. The release is MIT licensed under the restored Telometer notice in `LICENSE.txt`.
@@ -0,0 +1,108 @@
1
+ # Telometer 2.0.3
2
+
3
+ A tool for measuring chromosome-specific telomeres from long-read alignments.
4
+
5
+ [Telometer Github](https://github.com/santiago-es/Telometer)
6
+
7
+ Version 2.0.3 simplifies the main variant-output table and adds individual tract lengths and a fractional first-tract position. Telomere measurement, alignment selection, variant-tract qualification, and enrichment accounting are unchanged from the uploaded 2.0.2 baseline.
8
+
9
+ ## Install and run
10
+
11
+ The distribution retains its Python **>=3.8** declaration and unpinned numpy, pandas, pysam, regex, and scipy dependencies. Validation for this revision uses **Python 3.11.13**; this does not establish compatibility with older interpreters or every platform/dependency combination. The standalone bundle includes the previously tested dependency pins in `requirements.txt`.
12
+
13
+ In an activated Python environment, install a downloaded release file:
14
+
15
+ ```bash
16
+ uv pip install ./telometer-2.0.3-py3-none-any.whl
17
+ # Or build/install the source distribution:
18
+ uv pip install ./telometer-2.0.3.tar.gz
19
+
20
+ telometer --version
21
+ ```
22
+
23
+ The version command prints `Telometer v2.0.3`. Run on a sorted BAM aligned to a confirmed compatible reference:
24
+
25
+ ```bash
26
+ # WGS; use -m 1000 for telomere capture libraries.
27
+ telometer -b sample.sorted.bam -o telomeres.tsv -m 4000 -g 20 -t 2 -l 1
28
+
29
+ # Optional variant motif and independently optional enrichment:
30
+ telometer -b sample.sorted.bam -o telomeres_variants.tsv -m 4000 -g 20 -t 2 -l 1 \
31
+ --variant-motif TGCGGT --min-variant-units 2 -e
32
+ ```
33
+
34
+ `TGCGGT` is an example, not an inferred or default motif. Both optional features are off unless requested. `-e` / `--enrichment` is a Boolean switch with no value. The existing minimum-length default is 1000 bp; the gap default is 20. `-l` is a nominal batch-size setting in GiB, **not a total-memory limit**. With enrichment enabled, memory also scales with the number of unique read IDs. Choose resources using a representative subset.
35
+
36
+ The console entry point is `telometer.telometer:run_telometer`. Package-context alternatives are `python -m telometer.telometer` and `from telometer.telometer import process_bam_file`. There is no `python -m telometer` launcher or root-level function re-export in this package.
37
+
38
+ For the standalone ZIP, extract **all five files together**, install its requirements, and invoke `python telometer.py`. Its two helper modules must remain adjacent to the caller. The separate drop-in package module uses relative imports and is not a self-contained standalone script.
39
+
40
+ ## Main TSV
41
+
42
+ With variant mode and enrichment both enabled, columns are exactly:
43
+
44
+ ```text
45
+ chromosome
46
+ reference_start
47
+ reference_end
48
+ telomere_length
49
+ read_id
50
+ mapping_quality
51
+ read_length
52
+ arm
53
+ direction
54
+ variant_motif
55
+ variant_present
56
+ variant_tract_count
57
+ pre_variant_bp
58
+ telomeres_per_gb
59
+ variant_tract_lengths
60
+ percent_pre_variant
61
+ ```
62
+
63
+ Without `-e`, `telomeres_per_gb` is omitted. Without variant mode, all variant-specific columns are omitted. The four mode widths are **9 / 10 / 15 / 16** for neither / enrichment only / variants only / both. Empty tables retain the appropriate headers. Missing values in the main TSV are the literal **`NA`**; genuine zeros are preserved. Main row order may vary across worker runs, so compare by read ID.
64
+
65
+ ### Individual tract lengths
66
+
67
+ `variant_tract_lengths` contains integer base-pair spans, separated by commas without spaces, in the existing companion `tract_id` order (increasing original-read query coordinates). There is one entry per qualifying tract. These are spans, not six-base repeat counts or merged/union coverage. Separately counted overlapping tracts remain separate, and lengths are not rounded to multiples of six. Reads without qualifying tracts have `NA`.
68
+
69
+ ### Fractional first-tract position
70
+
71
+ `percent_pre_variant` is a **0–1 fraction**, not a 0–100 percentage. It describes the first qualifying tract's position from the called telomere's subtelomeric-facing end toward its distal end. In the existing original-orientation coordinate frame, let `T0` and `T1` be the selected telomere boundaries:
72
+
73
+ - Right-terminal telomere: `(minimum tract start - T0) / telomere_length`.
74
+ - Left-terminal telomere: `(T1 - maximum tract end) / telomere_length`.
75
+
76
+ The coordinate frame includes consistent recorded hard-clip offsets. No qualifying tract or an ambiguous/unidentifiable terminal side gives `NA`. A tract at the proximal boundary gives a genuine zero. The lengths list stays in query-coordinate order even when the proximal-first tract is its last entry.
77
+
78
+ Unlike the unchanged `pre_variant_bp`, the new fraction **does not require a supported alignment/repeat-free-flank anchor**. It can therefore be numeric when `pre_variant_bp` is `NA`. It measures position within the called telomere interval, not a verified physical subtelomeric junction or historical telomere length. Detection and tract-support thresholds are unchanged.
79
+
80
+ ## Companion table and enrichment
81
+
82
+ Variant mode still writes `<output_stem>_variant_tracts.tsv` with its unchanged 20-column schema, per-tract values, and missing-value formatting. The eight removed main-table coverage/diagnostic fields are not used to change calls or suppress internal diagnostics. Use a fresh output stem to avoid confusing an old companion with a new variant-disabled run.
83
+
84
+ Enrichment remains:
85
+
86
+ `final measured unique read-ID count * 1,000,000,000 / nonredundant recorded read bases in the BAM`
87
+
88
+ Each QNAME contributes one consistent recorded full length before filtering; repeated alignments do not multiply bases. Query-consuming CIGAR operations and recorded hard clips determine full length when available. Unresolved/conflicting lengths, unusable IDs, or paired-end input can make the aggregate unavailable; valid measurements are still written with `NA` enrichment. Positive recorded bases with zero calls give rate zero; an empty/zero-base BAM has unavailable rate. The sample-wide value is repeated on measured rows, not calculated independently per read. Preserve the console log for sample totals when the output has no rows.
89
+
90
+ The BAM cannot recover reads removed upstream or trimming that is absent from its metadata. This rate is not necessarily total instrument yield or a fold-enrichment comparison. Software regression checks are not independent biological validation of variant status, telomere boundaries, or positional interpretation.
91
+
92
+ ## Build and manual publication
93
+
94
+ The supplied flat layout and `setuptools>=61,<76` backend policy are retained. Build in an activated environment:
95
+
96
+ ```bash
97
+ uv pip install "build==1.5.0"
98
+ python -m build
99
+ ```
100
+
101
+ Use current Twine and packaging when checking metadata:
102
+
103
+ ```bash
104
+ uv pip install --upgrade "twine>=6.1.0" "packaging>=24.2"
105
+ python -m twine check --strict dist/telometer-2.0.3-py3-none-any.whl dist/telometer-2.0.3.tar.gz
106
+ ```
107
+
108
+ Publishing is a separate maintainer action; these files do not update GitHub or PyPI automatically. The release is MIT licensed under the restored Telometer notice in `LICENSE.txt`.
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
8
8
 
9
9
  [project]
10
10
  name = "telometer"
11
- version = "2.0.2"
11
+ version = "2.0.3"
12
12
  description = "Quantitative digital telomere measurement from nanopore long reads"
13
13
  readme = { file = "README.md", content-type = "text/markdown" }
14
14
  requires-python = ">=3.8"
@@ -1,3 +1,3 @@
1
1
  """Telometer package."""
2
2
 
3
- __version__ = "2.0.2"
3
+ __version__ = "2.0.3"
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- # Telometer v2.0
2
+ # Telometer v2.0.3
3
3
 
4
4
  # Created by: Santiago E Sanchez
5
5
  # Artandi Lab, Stanford University, 2024
@@ -8,7 +8,7 @@
8
8
 
9
9
  # Simple Usage: telometer -b sorted_t2t.bam -o output.tsv
10
10
 
11
- __version__ = "2.0.2"
11
+ __version__ = "2.0.3"
12
12
 
13
13
  import pysam
14
14
  from pathlib import Path
@@ -354,6 +354,56 @@ class EnrichmentCounter:
354
354
  'warning': 'Enrichment unavailable: ' + '; '.join(reasons) if reasons else None}
355
355
 
356
356
 
357
+ _MAIN_VARIANT_COLUMNS = ['variant_motif', 'variant_present', 'variant_tract_count', 'pre_variant_bp']
358
+
359
+
360
+ def _variant_output_fields(read_result):
361
+ """Format existing winning tracts without changing calls or anchor checks.
362
+
363
+ The fraction uses the called telomere's proximal-facing boundary, independently
364
+ of whether the original pre_variant_bp proxy passes its stricter anchor gates.
365
+ All coordinates already share the original-read frame and hard-clip offset.
366
+ """
367
+ tracts = read_result['_variant_tracts']
368
+ if (len(tracts) != read_result['variant_tract_count'] or
369
+ bool(tracts) != read_result['variant_present']):
370
+ raise ValueError('Variant tract count/presence disagrees with the existing tract rows')
371
+ if not tracts:
372
+ return None, None
373
+
374
+ details = read_result['_variant_details']
375
+ start, end = details['query_start_forward'], details['query_end_forward']
376
+ telomere_length = read_result['telomere_length']
377
+ if not 0 <= start < end or telomere_length <= 0 or end-start != telomere_length:
378
+ raise ValueError('Inconsistent called-telomere coordinates for variant output')
379
+
380
+ lengths = []
381
+ previous_start = None
382
+ for index, tract in enumerate(tracts, 1):
383
+ tract_start, tract_end = tract['query_start_forward'], tract['query_end_forward']
384
+ span = tract['span_bp']
385
+ if (not isinstance(span, int) or isinstance(span, bool) or
386
+ not start <= tract_start < tract_end <= end or span != tract_end-tract_start):
387
+ raise ValueError('Inconsistent variant tract coordinates or base-pair span')
388
+ if tract['tract_id'] != index or (previous_start is not None and tract_start < previous_start):
389
+ raise ValueError('Variant tract rows are not in their existing tract-ID/query order')
390
+ lengths.append(str(span))
391
+ previous_start = tract_start
392
+
393
+ length_list = ','.join(lengths)
394
+ side = details['telomeric_query_side']
395
+ if side == 'right':
396
+ distance = min(tract['query_start_forward'] for tract in tracts)-start
397
+ elif side == 'left':
398
+ distance = end-max(tract['query_end_forward'] for tract in tracts)
399
+ else:
400
+ return length_list, None
401
+ fraction = distance / telomere_length
402
+ if not 0 <= fraction <= 1:
403
+ raise ValueError('Variant fractional position lies outside the called telomere')
404
+ return length_list, fraction
405
+
406
+
357
407
  def process_bam_file(bam_file_path, output_file_path, max_gap_length=20, min_read_len=1000, num_processes=8, memory_limit_gb=8,
358
408
  variant_motif=None, min_variant_units=None, enrichment=False):
359
409
  variant_motif, min_variant_units = validate_variant_options(variant_motif, min_variant_units)
@@ -447,11 +497,16 @@ def process_bam_file(bam_file_path, output_file_path, max_gap_length=20, min_rea
447
497
  bam_file.close()
448
498
 
449
499
  enrichment_summary = enrichment_counter.summarize(len(read_results)) if enrichment_counter is not None else None
450
- results_df = pd.DataFrame(list(read_results.values()), columns=BASE_COLUMNS + (VARIANT_COLUMNS if variant_motif is not None else []))
500
+ output_records = list(read_results.values())
501
+ results_df = pd.DataFrame(output_records, columns=BASE_COLUMNS + (_MAIN_VARIANT_COLUMNS if variant_motif is not None else []))
451
502
  if enrichment_summary is not None:
452
503
  rate = enrichment_summary['telomeres_per_gb']
453
504
  results_df['telomeres_per_gb'] = rate if rate is not None else np.nan
454
- results_df.to_csv(output_file_path, sep='\t', index=False)
505
+ if variant_motif is not None:
506
+ variant_output = [_variant_output_fields(result) for result in output_records]
507
+ results_df['variant_tract_lengths'] = [fields[0] for fields in variant_output]
508
+ results_df['percent_pre_variant'] = [fields[1] for fields in variant_output]
509
+ results_df.to_csv(output_file_path, sep='\t', index=False, na_rep='NA')
455
510
  if variant_motif is not None:
456
511
  tract_rows = [tract for result in read_results.values() for tract in result['_variant_tracts']]
457
512
  tract_path = Path(output_file_path).with_name(Path(output_file_path).stem + '_variant_tracts.tsv')
@@ -0,0 +1,155 @@
1
+ Metadata-Version: 2.1
2
+ Name: telometer
3
+ Version: 2.0.3
4
+ Summary: Quantitative digital telomere measurement from nanopore long reads
5
+ Author-email: "Santiago E. Sanchez" <santy.esanchez@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2023 santiago-es
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Classifier: Development Status :: 4 - Beta
29
+ Classifier: Intended Audience :: Science/Research
30
+ Classifier: License :: OSI Approved :: MIT License
31
+ Classifier: Operating System :: OS Independent
32
+ Classifier: Programming Language :: Python :: 3
33
+ Classifier: Programming Language :: Python :: 3.8
34
+ Classifier: Programming Language :: Python :: 3.9
35
+ Classifier: Programming Language :: Python :: 3.10
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
39
+ Requires-Python: >=3.8
40
+ Description-Content-Type: text/markdown
41
+ License-File: LICENSE.txt
42
+ Requires-Dist: numpy
43
+ Requires-Dist: pandas
44
+ Requires-Dist: pysam
45
+ Requires-Dist: regex
46
+ Requires-Dist: scipy
47
+
48
+ # Telometer 2.0.3
49
+
50
+ A tool for measuring chromosome-specific telomeres from long-read alignments.
51
+
52
+ [Telometer Github](https://github.com/santiago-es/Telometer)
53
+
54
+ Version 2.0.3 simplifies the main variant-output table and adds individual tract lengths and a fractional first-tract position. Telomere measurement, alignment selection, variant-tract qualification, and enrichment accounting are unchanged from the uploaded 2.0.2 baseline.
55
+
56
+ ## Install and run
57
+
58
+ The distribution retains its Python **>=3.8** declaration and unpinned numpy, pandas, pysam, regex, and scipy dependencies. Validation for this revision uses **Python 3.11.13**; this does not establish compatibility with older interpreters or every platform/dependency combination. The standalone bundle includes the previously tested dependency pins in `requirements.txt`.
59
+
60
+ In an activated Python environment, install a downloaded release file:
61
+
62
+ ```bash
63
+ uv pip install ./telometer-2.0.3-py3-none-any.whl
64
+ # Or build/install the source distribution:
65
+ uv pip install ./telometer-2.0.3.tar.gz
66
+
67
+ telometer --version
68
+ ```
69
+
70
+ The version command prints `Telometer v2.0.3`. Run on a sorted BAM aligned to a confirmed compatible reference:
71
+
72
+ ```bash
73
+ # WGS; use -m 1000 for telomere capture libraries.
74
+ telometer -b sample.sorted.bam -o telomeres.tsv -m 4000 -g 20 -t 2 -l 1
75
+
76
+ # Optional variant motif and independently optional enrichment:
77
+ telometer -b sample.sorted.bam -o telomeres_variants.tsv -m 4000 -g 20 -t 2 -l 1 \
78
+ --variant-motif TGCGGT --min-variant-units 2 -e
79
+ ```
80
+
81
+ `TGCGGT` is an example, not an inferred or default motif. Both optional features are off unless requested. `-e` / `--enrichment` is a Boolean switch with no value. The existing minimum-length default is 1000 bp; the gap default is 20. `-l` is a nominal batch-size setting in GiB, **not a total-memory limit**. With enrichment enabled, memory also scales with the number of unique read IDs. Choose resources using a representative subset.
82
+
83
+ The console entry point is `telometer.telometer:run_telometer`. Package-context alternatives are `python -m telometer.telometer` and `from telometer.telometer import process_bam_file`. There is no `python -m telometer` launcher or root-level function re-export in this package.
84
+
85
+ For the standalone ZIP, extract **all five files together**, install its requirements, and invoke `python telometer.py`. Its two helper modules must remain adjacent to the caller. The separate drop-in package module uses relative imports and is not a self-contained standalone script.
86
+
87
+ ## Main TSV
88
+
89
+ With variant mode and enrichment both enabled, columns are exactly:
90
+
91
+ ```text
92
+ chromosome
93
+ reference_start
94
+ reference_end
95
+ telomere_length
96
+ read_id
97
+ mapping_quality
98
+ read_length
99
+ arm
100
+ direction
101
+ variant_motif
102
+ variant_present
103
+ variant_tract_count
104
+ pre_variant_bp
105
+ telomeres_per_gb
106
+ variant_tract_lengths
107
+ percent_pre_variant
108
+ ```
109
+
110
+ Without `-e`, `telomeres_per_gb` is omitted. Without variant mode, all variant-specific columns are omitted. The four mode widths are **9 / 10 / 15 / 16** for neither / enrichment only / variants only / both. Empty tables retain the appropriate headers. Missing values in the main TSV are the literal **`NA`**; genuine zeros are preserved. Main row order may vary across worker runs, so compare by read ID.
111
+
112
+ ### Individual tract lengths
113
+
114
+ `variant_tract_lengths` contains integer base-pair spans, separated by commas without spaces, in the existing companion `tract_id` order (increasing original-read query coordinates). There is one entry per qualifying tract. These are spans, not six-base repeat counts or merged/union coverage. Separately counted overlapping tracts remain separate, and lengths are not rounded to multiples of six. Reads without qualifying tracts have `NA`.
115
+
116
+ ### Fractional first-tract position
117
+
118
+ `percent_pre_variant` is a **0–1 fraction**, not a 0–100 percentage. It describes the first qualifying tract's position from the called telomere's subtelomeric-facing end toward its distal end. In the existing original-orientation coordinate frame, let `T0` and `T1` be the selected telomere boundaries:
119
+
120
+ - Right-terminal telomere: `(minimum tract start - T0) / telomere_length`.
121
+ - Left-terminal telomere: `(T1 - maximum tract end) / telomere_length`.
122
+
123
+ The coordinate frame includes consistent recorded hard-clip offsets. No qualifying tract or an ambiguous/unidentifiable terminal side gives `NA`. A tract at the proximal boundary gives a genuine zero. The lengths list stays in query-coordinate order even when the proximal-first tract is its last entry.
124
+
125
+ Unlike the unchanged `pre_variant_bp`, the new fraction **does not require a supported alignment/repeat-free-flank anchor**. It can therefore be numeric when `pre_variant_bp` is `NA`. It measures position within the called telomere interval, not a verified physical subtelomeric junction or historical telomere length. Detection and tract-support thresholds are unchanged.
126
+
127
+ ## Companion table and enrichment
128
+
129
+ Variant mode still writes `<output_stem>_variant_tracts.tsv` with its unchanged 20-column schema, per-tract values, and missing-value formatting. The eight removed main-table coverage/diagnostic fields are not used to change calls or suppress internal diagnostics. Use a fresh output stem to avoid confusing an old companion with a new variant-disabled run.
130
+
131
+ Enrichment remains:
132
+
133
+ `final measured unique read-ID count * 1,000,000,000 / nonredundant recorded read bases in the BAM`
134
+
135
+ Each QNAME contributes one consistent recorded full length before filtering; repeated alignments do not multiply bases. Query-consuming CIGAR operations and recorded hard clips determine full length when available. Unresolved/conflicting lengths, unusable IDs, or paired-end input can make the aggregate unavailable; valid measurements are still written with `NA` enrichment. Positive recorded bases with zero calls give rate zero; an empty/zero-base BAM has unavailable rate. The sample-wide value is repeated on measured rows, not calculated independently per read. Preserve the console log for sample totals when the output has no rows.
136
+
137
+ The BAM cannot recover reads removed upstream or trimming that is absent from its metadata. This rate is not necessarily total instrument yield or a fold-enrichment comparison. Software regression checks are not independent biological validation of variant status, telomere boundaries, or positional interpretation.
138
+
139
+ ## Build and manual publication
140
+
141
+ The supplied flat layout and `setuptools>=61,<76` backend policy are retained. Build in an activated environment:
142
+
143
+ ```bash
144
+ uv pip install "build==1.5.0"
145
+ python -m build
146
+ ```
147
+
148
+ Use current Twine and packaging when checking metadata:
149
+
150
+ ```bash
151
+ uv pip install --upgrade "twine>=6.1.0" "packaging>=24.2"
152
+ python -m twine check --strict dist/telometer-2.0.3-py3-none-any.whl dist/telometer-2.0.3.tar.gz
153
+ ```
154
+
155
+ Publishing is a separate maintainer action; these files do not update GitHub or PyPI automatically. The release is MIT licensed under the restored Telometer notice in `LICENSE.txt`.
@@ -1,6 +1,7 @@
1
1
  LICENSE.txt
2
2
  README.md
3
3
  pyproject.toml
4
+ setup.cfg
4
5
  telometer/__init__.py
5
6
  telometer/telometer.py
6
7
  telometer/telometer_variant_support.py
telometer-2.0.2/PKG-INFO DELETED
@@ -1,48 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: telometer
3
- Version: 2.0.2
4
- Summary: Quantitative digital telomere measurement from nanopore long reads
5
- Author-email: "Santiago E. Sanchez" <santy.esanchez@gmail.com>
6
- License: Copyright (c) 2024 The Python Packaging Authority
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy
9
- of this software and associated documentation files (the "Software"), to deal
10
- in the Software without restriction, including without limitation the rights
11
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- copies of the Software, and to permit persons to whom the Software is
13
- furnished to do so, subject to the following conditions:
14
-
15
- The above copyright notice and this permission notice shall be included in all
16
- copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- SOFTWARE.
25
-
26
- Classifier: Development Status :: 4 - Beta
27
- Classifier: Intended Audience :: Science/Research
28
- Classifier: License :: OSI Approved :: MIT License
29
- Classifier: Operating System :: OS Independent
30
- Classifier: Programming Language :: Python :: 3
31
- Classifier: Programming Language :: Python :: 3.8
32
- Classifier: Programming Language :: Python :: 3.9
33
- Classifier: Programming Language :: Python :: 3.10
34
- Classifier: Programming Language :: Python :: 3.11
35
- Classifier: Programming Language :: Python :: 3.12
36
- Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
37
- Requires-Python: >=3.8
38
- Description-Content-Type: text/markdown
39
- License-File: LICENSE.txt
40
- Requires-Dist: numpy
41
- Requires-Dist: pandas
42
- Requires-Dist: pysam
43
- Requires-Dist: regex
44
- Requires-Dist: scipy
45
-
46
- A simple tool for measuring chromosome-specific telomeres from long-read alignments.
47
-
48
- [Telometer Github](https://github.com/santiago-es/Telometer)
telometer-2.0.2/README.md DELETED
@@ -1,3 +0,0 @@
1
- A simple tool for measuring chromosome-specific telomeres from long-read alignments.
2
-
3
- [Telometer Github](https://github.com/santiago-es/Telometer)
@@ -1,48 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: telometer
3
- Version: 2.0.2
4
- Summary: Quantitative digital telomere measurement from nanopore long reads
5
- Author-email: "Santiago E. Sanchez" <santy.esanchez@gmail.com>
6
- License: Copyright (c) 2024 The Python Packaging Authority
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy
9
- of this software and associated documentation files (the "Software"), to deal
10
- in the Software without restriction, including without limitation the rights
11
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- copies of the Software, and to permit persons to whom the Software is
13
- furnished to do so, subject to the following conditions:
14
-
15
- The above copyright notice and this permission notice shall be included in all
16
- copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- SOFTWARE.
25
-
26
- Classifier: Development Status :: 4 - Beta
27
- Classifier: Intended Audience :: Science/Research
28
- Classifier: License :: OSI Approved :: MIT License
29
- Classifier: Operating System :: OS Independent
30
- Classifier: Programming Language :: Python :: 3
31
- Classifier: Programming Language :: Python :: 3.8
32
- Classifier: Programming Language :: Python :: 3.9
33
- Classifier: Programming Language :: Python :: 3.10
34
- Classifier: Programming Language :: Python :: 3.11
35
- Classifier: Programming Language :: Python :: 3.12
36
- Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
37
- Requires-Python: >=3.8
38
- Description-Content-Type: text/markdown
39
- License-File: LICENSE.txt
40
- Requires-Dist: numpy
41
- Requires-Dist: pandas
42
- Requires-Dist: pysam
43
- Requires-Dist: regex
44
- Requires-Dist: scipy
45
-
46
- A simple tool for measuring chromosome-specific telomeres from long-read alignments.
47
-
48
- [Telometer Github](https://github.com/santiago-es/Telometer)
File without changes