twobitreader-rs 0.2.2__tar.gz → 0.2.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.
@@ -4,10 +4,25 @@ All notable changes to this project are documented here.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
6
6
  project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The Rust
7
- crate `twobitreader` and the Python package `twobitreader_rs` share a version number.
7
+ crate `twobitreader` and the Python package `twobitreader-rs` share a version number.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.2.3] - 2026-11-03
12
+
13
+ ### Fixed
14
+
15
+ - `TwobitReader::open` no longer rejects a valid 2bit file that contains exactly one sequence
16
+ record. The record's data starts immediately after the index, so its offset equals the end
17
+ of the index, which the offset check wrongly treated as invalid.
18
+ - Missing word and a misplaced sentence in the Benchmarks section of the documentation.
19
+
20
+ ### Changed
21
+
22
+ - README.md is now generated from the crate documentation with `cargo rdme`, and CI checks
23
+ that it is up to date. The badges moved from the crate documentation into README.md, so
24
+ they no longer appear on docs.rs.
25
+
11
26
  ## [0.2.2] - 2026-10-01
12
27
 
13
28
  ### Added
@@ -16,7 +31,7 @@ crate `twobitreader` and the Python package `twobitreader_rs` share a version nu
16
31
 
17
32
  ## [0.2.1] - 2026-10-01
18
33
 
19
- First release of `twobitreader_rs` on PyPI. There are no library changes; 0.2.0 reached
34
+ First release of `twobitreader-rs` on PyPI. There are no library changes; 0.2.0 reached
20
35
  crates.io before the wheel-building workflow was in place, so it was never published for
21
36
  Python.
22
37
 
@@ -31,13 +46,13 @@ Python.
31
46
 
32
47
  ## [0.2.0] - 2026-10-01
33
48
 
34
- `twobitreader` is now available from Python as **`twobitreader_rs`**, built with PyO3 and
49
+ `twobitreader` is now available from Python as **`twobitreader-rs`**, built with PyO3 and
35
50
  published as a wheel. The Python API mirrors the Rust one, with speed close to pure Rust.
36
51
 
37
52
  ### Added
38
53
 
39
- - **Python bindings** (`twobitreader_rs`), exposing `TwobitReader` and `reverse_complement`.
40
- Available for CPython 3.9+ on Linux, macOS and Windows.
54
+ - **Python bindings** (`import twobitreader_rs`), exposing `TwobitReader` and
55
+ `reverse_complement`. Available for CPython 3.9+ on Linux, macOS and Windows.
41
56
  - **Free-threaded CPython support.** The extension is marked `gil_used = false` and the
42
57
  reader is immutable and shareable. A thread pool over batches scales across cores on a
43
58
  free-threaded build.
@@ -71,7 +86,8 @@ extraction with `get_batch`, exon concatenation with `concat`, reverse complemen
71
86
  `prefetch` for cold files. Sequence records are parsed lazily so that opening a large file
72
87
  stays cheap. No git tag was made for this version.
73
88
 
74
- [Unreleased]: https://github.com/andrewdelong/twobitreader-rust/compare/v0.2.2...HEAD
89
+ [Unreleased]: https://github.com/andrewdelong/twobitreader-rust/compare/v0.2.3...HEAD
90
+ [0.2.3]: https://github.com/andrewdelong/twobitreader-rust/compare/v0.2.2...v0.2.3
75
91
  [0.2.2]: https://github.com/andrewdelong/twobitreader-rust/compare/v0.2.1...v0.2.2
76
92
  [0.2.1]: https://github.com/andrewdelong/twobitreader-rust/compare/v0.2.0...v0.2.1
77
93
  [0.2.0]: https://github.com/andrewdelong/twobitreader-rust/compare/v0.1.1...v0.2.0
@@ -22,9 +22,9 @@ checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
22
22
 
23
23
  [[package]]
24
24
  name = "crc32fast"
25
- version = "1.5.2"
25
+ version = "1.5.4"
26
26
  source = "registry+https://github.com/rust-lang/crates.io-index"
27
- checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78"
27
+ checksum = "5f97d3416d5337d15c4b0d78c8c91df922ca143f57ec20e2d1c188333047ef04"
28
28
  dependencies = [
29
29
  "cfg-if",
30
30
  ]
@@ -56,9 +56,9 @@ checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
56
56
 
57
57
  [[package]]
58
58
  name = "either"
59
- version = "1.18.0"
59
+ version = "1.19.0"
60
60
  source = "registry+https://github.com/rust-lang/crates.io-index"
61
- checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
61
+ checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
62
62
 
63
63
  [[package]]
64
64
  name = "flate2"
@@ -88,15 +88,15 @@ dependencies = [
88
88
 
89
89
  [[package]]
90
90
  name = "libc"
91
- version = "0.2.189"
91
+ version = "0.2.191"
92
92
  source = "registry+https://github.com/rust-lang/crates.io-index"
93
- checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
93
+ checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
94
94
 
95
95
  [[package]]
96
96
  name = "memmap2"
97
- version = "0.9.11"
97
+ version = "0.9.12"
98
98
  source = "registry+https://github.com/rust-lang/crates.io-index"
99
- checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0"
99
+ checksum = "6b0ca1155a9ecc25aa12e8313a119f32edf0255fea2f44839c4ac0a12b2ac157"
100
100
  dependencies = [
101
101
  "libc",
102
102
  ]
@@ -134,9 +134,9 @@ dependencies = [
134
134
 
135
135
  [[package]]
136
136
  name = "pyo3"
137
- version = "0.29.3"
137
+ version = "0.30.1"
138
138
  source = "registry+https://github.com/rust-lang/crates.io-index"
139
- checksum = "700d18fa267b73b9b521fd7e13580e2f446916f176cacee1ab63fcc8191f1655"
139
+ checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4"
140
140
  dependencies = [
141
141
  "libc",
142
142
  "once_cell",
@@ -148,18 +148,18 @@ dependencies = [
148
148
 
149
149
  [[package]]
150
150
  name = "pyo3-build-config"
151
- version = "0.29.3"
151
+ version = "0.30.1"
152
152
  source = "registry+https://github.com/rust-lang/crates.io-index"
153
- checksum = "7b3fc0c4d08f6bb10e71fe39dfb9e2f59c6eb6854e22ec8092f50c69a4499adb"
153
+ checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700"
154
154
  dependencies = [
155
155
  "target-lexicon",
156
156
  ]
157
157
 
158
158
  [[package]]
159
159
  name = "pyo3-ffi"
160
- version = "0.29.3"
160
+ version = "0.30.1"
161
161
  source = "registry+https://github.com/rust-lang/crates.io-index"
162
- checksum = "dfc0b8e19df29aad7086cf977bb0c2a2f143e30567eb113e9cf72b62ca698330"
162
+ checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4"
163
163
  dependencies = [
164
164
  "libc",
165
165
  "pyo3-build-config",
@@ -167,9 +167,9 @@ dependencies = [
167
167
 
168
168
  [[package]]
169
169
  name = "pyo3-macros"
170
- version = "0.29.3"
170
+ version = "0.30.1"
171
171
  source = "registry+https://github.com/rust-lang/crates.io-index"
172
- checksum = "6100e8a4b5eba53afaa5ed078364851a0b2499c553a44c31026b929049b49dc6"
172
+ checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60"
173
173
  dependencies = [
174
174
  "proc-macro2",
175
175
  "pyo3-macros-backend",
@@ -179,9 +179,9 @@ dependencies = [
179
179
 
180
180
  [[package]]
181
181
  name = "pyo3-macros-backend"
182
- version = "0.29.3"
182
+ version = "0.30.1"
183
183
  source = "registry+https://github.com/rust-lang/crates.io-index"
184
- checksum = "6143877a16e82b5a727b7127ff4cd86858a24a28d745d72f43e6f227c7b1bdb3"
184
+ checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b"
185
185
  dependencies = [
186
186
  "heck",
187
187
  "proc-macro2",
@@ -238,9 +238,9 @@ checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
238
238
 
239
239
  [[package]]
240
240
  name = "syn"
241
- version = "2.0.119"
241
+ version = "3.0.9"
242
242
  source = "registry+https://github.com/rust-lang/crates.io-index"
243
- checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
243
+ checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
244
244
  dependencies = [
245
245
  "proc-macro2",
246
246
  "quote",
@@ -255,7 +255,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
255
255
 
256
256
  [[package]]
257
257
  name = "twobitreader"
258
- version = "0.2.2"
258
+ version = "0.2.3"
259
259
  dependencies = [
260
260
  "byteorder",
261
261
  "flate2",
@@ -271,9 +271,9 @@ dependencies = [
271
271
 
272
272
  [[package]]
273
273
  name = "unicode-ident"
274
- version = "1.0.26"
274
+ version = "1.0.27"
275
275
  source = "registry+https://github.com/rust-lang/crates.io-index"
276
- checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
276
+ checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
277
277
 
278
278
  [[package]]
279
279
  name = "windows-link"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "twobitreader"
3
- version = "0.2.2"
3
+ version = "0.2.3"
4
4
  edition = "2024"
5
5
  authors = ["Andrew Delong <andrew.delong@gmail.com>"]
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: twobitreader-rs
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: Operating System :: POSIX :: Linux
@@ -1,5 +1,13 @@
1
1
  # twobitreader
2
2
 
3
+ [![CI](https://github.com/andrewdelong/twobitreader-rust/actions/workflows/ci.yml/badge.svg)](https://github.com/andrewdelong/twobitreader-rust/actions/workflows/ci.yml)
4
+ ![Windows](https://img.shields.io/badge/Windows-supported-blue?logo=windows)
5
+ ![macOS](https://img.shields.io/badge/macOS-supported-blue?logo=apple)
6
+ ![Linux](https://img.shields.io/badge/Linux-supported-blue?logo=linux)
7
+ [![Conda Version](https://img.shields.io/conda/vn/conda-forge/twobitreader-rs.svg)](https://anaconda.org/conda-forge/twobitreader-rs)
8
+ [![PyPI Version](https://img.shields.io/pypi/v/twobitreader-rs.svg)](https://pypi.org/project/twobitreader-rs/)
9
+
10
+ <!-- cargo-rdme start -->
3
11
 
4
12
  This crate provides fast DNA sequence extraction from 2bit files, a
5
13
  [standard format](http://genome.ucsc.edu/FAQ/FAQformat.html#format7) in bioinformatics.
@@ -10,13 +18,6 @@ It is also available as a Python package named `twobitreader-rs`.
10
18
  The focus is raw reading from 2bit, but fast concatenation and reverse-complement methods
11
19
  are also provided to make higher-level use cases easier.
12
20
 
13
- [![CI](https://github.com/andrewdelong/twobitreader-rust/actions/workflows/ci.yml/badge.svg)](https://github.com/andrewdelong/twobitreader-rust/actions/workflows/ci.yml)
14
- ![Windows](https://img.shields.io/badge/Windows-supported-blue?logo=windows)
15
- ![macOS](https://img.shields.io/badge/macOS-supported-blue?logo=apple)
16
- ![Linux](https://img.shields.io/badge/Linux-supported-blue?logo=linux)
17
- [![Conda Version](https://img.shields.io/conda/vn/conda-forge/twobitreader-rs.svg)](https://anaconda.org/conda-forge/twobitreader-rs)
18
- [![PyPI Version](https://img.shields.io/pypi/v/twobitreader-rs.svg)](https://pypi.org/project/twobitreader-rs/)
19
-
20
21
  ## Examples
21
22
 
22
23
  **Extracting sequences** is straightforward:
@@ -89,13 +90,13 @@ Speed depends on parallelism and page cache (hot vs cold):
89
90
  - **cold** runs represent a first run of a genomics pipeline, bound by disk speed;
90
91
  - **prefetch** runs are cold but with a `prefetch` call preceding extraction.
91
92
 
92
- The table below shows running times in milliseconds. Experimental details are `BENCH.md`.
93
- This crate provides *twobitreader* (pure rust) and *twobitreader_rs* (python wrapper).
93
+ The table below shows running times in milliseconds. Experimental details are in `BENCH.md`.
94
+ This crate provides the *twobitreader* and *twobitreader-rs* rows.
94
95
 
95
96
  | EXONS | 1-thread / hot | 1-thread / cold | 1-thread / prefetch | 16-thread / hot | 16-thread / cold |
96
97
  |---|---:|---:|---:|---:|---:|
97
98
  | **twobitreader** (rs) | 90 | 1,700 | 180 | 10 | 190 |
98
- | **twobitreader_rs** (rs, py) | 100 | 1,900 | 190 | *27 | *210 |
99
+ | **twobitreader-rs** (rs, py) | 100 | 1,900 | 190 | *27 | *210 |
99
100
  | **py2bit** (c, py) | 220 | 2,800 | n/a | n/a | n/a |
100
101
  | **GenomeKit** (cpp, py) | 340 | 2,400 | n/a | n/a | n/a |
101
102
  | **twobit** (rs) | 390 | 3,500 | n/a | n/a | n/a |
@@ -106,7 +107,7 @@ This crate provides *twobitreader* (pure rust) and *twobitreader_rs* (python wra
106
107
  | TRANSCRIPTS | 1-thread / hot | 1-thread / cold | 1-thread / prefetch | 16-thread / hot | 16-thread / cold |
107
108
  |---|---:|---:|---:|---:|---:|
108
109
  | **twobitreader** (rs) | 140 | 1,700 | 230 | 13 | 190 |
109
- | **twobitreader_rs** (rs, py) | 180 | 2,100 | 310 | *27 | *220 |
110
+ | **twobitreader-rs** (rs, py) | 180 | 2,100 | 310 | *27 | *220 |
110
111
  | **py2bit** (c, py) | 490 | 3,600 | n/a | n/a | n/a |
111
112
  | **GenomeKit** (cpp, py) | 720 | 2,900 | n/a | n/a | n/a |
112
113
  | **twobit** (rs) | 930 | 1,900 | n/a | n/a | n/a |
@@ -126,8 +127,13 @@ Entries marked * were run in free-threaded Python.
126
127
 
127
128
  ## Use of AI
128
129
 
129
- Claude Code: generated the OS-specific prefetch loops; improved handling of corrupt or malicious files;
130
- documented the Python bindings and mirrored their tests and benchmark; improved error checking and
131
- propagation to Python more broadly; and generated the CI configurations.
130
+ The Rust library was written primarily by hand.
131
+
132
+ Claude was used to generated the OS-specific prefetch loops, to improve handling of
133
+ corrupt or malicious files, to document the Python bindings and mirrored their tests
134
+ and benchmark, to improved error checking and propagation to Python more broadly,
135
+ and generated the CI configurations.
136
+
137
+ <!-- cargo-rdme end -->
132
138
 
133
139
  License: MIT OR Apache-2.0
@@ -2,7 +2,6 @@
2
2
  #![deny(missing_docs)]
3
3
  #![deny(unreachable_pub)]
4
4
  #![warn(rust_2018_idioms)]
5
- //!
6
5
  //! This crate provides fast DNA sequence extraction from 2bit files, a
7
6
  //! [standard format](http://genome.ucsc.edu/FAQ/FAQformat.html#format7) in bioinformatics.
8
7
  //!
@@ -12,13 +11,6 @@
12
11
  //! The focus is raw reading from 2bit, but fast concatenation and reverse-complement methods
13
12
  //! are also provided to make higher-level use cases easier.
14
13
  //!
15
- //! [![CI](https://github.com/andrewdelong/twobitreader-rust/actions/workflows/ci.yml/badge.svg)](https://github.com/andrewdelong/twobitreader-rust/actions/workflows/ci.yml)
16
- //! ![Windows](https://img.shields.io/badge/Windows-supported-blue?logo=windows)
17
- //! ![macOS](https://img.shields.io/badge/macOS-supported-blue?logo=apple)
18
- //! ![Linux](https://img.shields.io/badge/Linux-supported-blue?logo=linux)
19
- //! [![Conda Version](https://img.shields.io/conda/vn/conda-forge/twobitreader-rs.svg)](https://anaconda.org/conda-forge/twobitreader-rs)
20
- //! [![PyPI Version](https://img.shields.io/pypi/v/twobitreader-rs.svg)](https://pypi.org/project/twobitreader-rs/)
21
- //!
22
14
  //! # Examples
23
15
  //!
24
16
  //! **Extracting sequences** is straightforward:
@@ -117,13 +109,13 @@
117
109
  //! - **cold** runs represent a first run of a genomics pipeline, bound by disk speed;
118
110
  //! - **prefetch** runs are cold but with a `prefetch` call preceding extraction.
119
111
  //!
120
- //! The table below shows running times in milliseconds. Experimental details are `BENCH.md`.
121
- //! This crate provides *twobitreader* (pure rust) and *twobitreader_rs* (python wrapper).
112
+ //! The table below shows running times in milliseconds. Experimental details are in `BENCH.md`.
113
+ //! This crate provides the *twobitreader* and *twobitreader-rs* rows.
122
114
  //!
123
115
  //! | EXONS | 1-thread / hot | 1-thread / cold | 1-thread / prefetch | 16-thread / hot | 16-thread / cold |
124
116
  //! |---|---:|---:|---:|---:|---:|
125
117
  //! | **twobitreader** (rs) | 90 | 1,700 | 180 | 10 | 190 |
126
- //! | **twobitreader_rs** (rs, py) | 100 | 1,900 | 190 | *27 | *210 |
118
+ //! | **twobitreader-rs** (rs, py) | 100 | 1,900 | 190 | *27 | *210 |
127
119
  //! | **py2bit** (c, py) | 220 | 2,800 | n/a | n/a | n/a |
128
120
  //! | **GenomeKit** (cpp, py) | 340 | 2,400 | n/a | n/a | n/a |
129
121
  //! | **twobit** (rs) | 390 | 3,500 | n/a | n/a | n/a |
@@ -134,7 +126,7 @@
134
126
  //! | TRANSCRIPTS | 1-thread / hot | 1-thread / cold | 1-thread / prefetch | 16-thread / hot | 16-thread / cold |
135
127
  //! |---|---:|---:|---:|---:|---:|
136
128
  //! | **twobitreader** (rs) | 140 | 1,700 | 230 | 13 | 190 |
137
- //! | **twobitreader_rs** (rs, py) | 180 | 2,100 | 310 | *27 | *220 |
129
+ //! | **twobitreader-rs** (rs, py) | 180 | 2,100 | 310 | *27 | *220 |
138
130
  //! | **py2bit** (c, py) | 490 | 3,600 | n/a | n/a | n/a |
139
131
  //! | **GenomeKit** (cpp, py) | 720 | 2,900 | n/a | n/a | n/a |
140
132
  //! | **twobit** (rs) | 930 | 1,900 | n/a | n/a | n/a |
@@ -154,9 +146,12 @@
154
146
  //!
155
147
  //! # Use of AI
156
148
  //!
157
- //! Claude Code: generated the OS-specific prefetch loops; improved handling of corrupt or malicious files;
158
- //! documented the Python bindings and mirrored their tests and benchmark; improved error checking and
159
- //! propagation to Python more broadly; and generated the CI configurations.
149
+ //! The Rust library was written primarily by hand.
150
+ //!
151
+ //! Claude was used to generated the OS-specific prefetch loops, to improve handling of
152
+ //! corrupt or malicious files, to document the Python bindings and mirrored their tests
153
+ //! and benchmark, to improved error checking and propagation to Python more broadly,
154
+ //! and generated the CI configurations.
160
155
 
161
156
  // Standard library
162
157
  use std::borrow::Borrow;
@@ -910,7 +905,7 @@ fn read_seqs_endian<B: ByteOrder>(mmap: &Mmap) -> io::Result<Vec<TwobitSequence>
910
905
  // Get the offset of the data arrays for this sequence
911
906
  let data_offset = cursor.read_u32::<B>()? as u64;
912
907
  let curr_offset = cursor.position();
913
- if data_offset <= curr_offset {
908
+ if data_offset < curr_offset {
914
909
  return Err(io::Error::new(InvalidData, "invalid data offset; file may be malformed."));
915
910
  }
916
911