Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
wasm:
wasm-pack build --target bundler --release gtars-wasm
wasm-pack build --target web --release gtars-wasm
jq '.name = "@databio/gtars" | .repository = {"type": "git", "url": "https://github.com/databio/gtars"}' gtars-wasm/pkg/package.json > tmp.json && mv tmp.json gtars-wasm/pkg/package.json

test:
Expand Down
6 changes: 3 additions & 3 deletions gtars-bbcache/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[package]
name = "gtars-bbcache"
version = "0.5.1"
version = "0.5.2"
edition = "2024"
description = "Rust implementation of bbcache: a caching system for BED files on bedbase.org"
license = "MIT"
repository = "https://github.com/databio/gtars"

[dependencies]
biocrs = "0.1.0"
reqwest = { version = "0.12.15", features = ["blocking"] }
ureq = "3.1.4"
shellexpand = "3"
tabled = "0.20.0"
dirs = "6.0.0"
Expand All @@ -18,7 +18,7 @@ anyhow = { workspace = true }
serde_json = { workspace = true }

# our code
gtars-core = { path = "../gtars-core", version="0.5.1" }
gtars-core = { path = "../gtars-core", version="0.5.3" }

[dev-dependencies]
rstest = "0.26.1"
Expand Down
9 changes: 7 additions & 2 deletions gtars-bbcache/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use anyhow::{Context, Ok, Result, anyhow};
use biocrs::biocache::BioCache;
use biocrs::models::{NewResource, Resource};

use reqwest::blocking::get;
use ureq::get;
use std::fs::{File, create_dir_all, read_dir, remove_dir, remove_file};
use std::io::{BufRead, BufReader, Error, ErrorKind, Write};
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -367,7 +367,12 @@ impl BBClient {
fn download_bedset_data(&self, bedset_id: &str) -> Result<Vec<String>> {
let bedset_url = format!("{}/v1/bedset/{}/bedfiles", self.bedbase_api, bedset_id);

let response = get(&bedset_url)?.text()?;
let response = get(&bedset_url)
.call()
.map_err(|e| anyhow!("Failed to GET {}: {}", bedset_url, e))?
.body_mut()
.read_to_string()
Comment on lines +373 to +374
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .body_mut().read_to_string() pattern is incorrect for ureq. The read_to_string() method from std::io::Read requires a mutable String buffer as an argument (e.g., read_to_string(&mut buffer)), but this code doesn't provide one.

For ureq 3.x, the correct pattern is to use .into_string() which consumes the response and returns Result<String, Error>:

let response = get(&bedset_url)
    .call()
    .map_err(|e| anyhow!("Failed to GET {}: {}", bedset_url, e))?
    .into_string()
    .map_err(|e| anyhow!("Failed to read response body for {}: {}", bedset_url, e))?;

This is more idiomatic, handles errors properly, and avoids the need for the intermediate .body_mut() call.

Suggested change
.body_mut()
.read_to_string()
.into_string()

Copilot uses AI. Check for mistakes.
.map_err(|e| anyhow!("Failed to read response body for {}: {}", bedset_url, e))?;

let json: serde_json::Value = serde_json::from_str(&response)?;

Expand Down
6 changes: 3 additions & 3 deletions gtars-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "gtars-core"
version = "0.5.2"
version = "0.5.3"
edition = "2021"
description = "Core library for gtars: tools for high performance genomic interval analysis"
license = "MIT"
Expand All @@ -9,7 +9,7 @@ repository = "https://github.com/databio/gtars"
[dependencies]
md-5 = "0.10.6"
num-traits = "0.2.19"
reqwest = { version = "0.12.23", features = ["blocking"], optional=true }
ureq = {version = "3.1.4", optional=true}
tokio = "1.47.1"
bigtools = { version = "0.5.6", optional = true }

Expand All @@ -24,4 +24,4 @@ tempfile = "3.21.0"
[features]
default = []
bigbed = ["dep:bigtools"]
http = ["dep:reqwest"]
http = ["dep:ureq"]
7 changes: 3 additions & 4 deletions gtars-core/src/models/region_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl TryFrom<String> for RegionSet {
type Error = anyhow::Error;

fn try_from(value: String) -> Result<Self> {
println!("Converting String to Path: {}", value);
// println!("Converting String to Path: {}", value);
RegionSet::try_from(Path::new(&value))
}
}
Expand Down Expand Up @@ -567,14 +567,13 @@ mod tests {
}

#[rstest]
#[ignore = "Failing but low priority for now"]
fn test_open_from_url() {
let file_path = String::from("https://github.com/databio/gtars/raw/refs/heads/master/gtars/tests/data/regionset/dummy.narrowPeak.bed.gz");
let file_path = String::from("https://www.encodeproject.org/files/ENCFF321QPN/@@download/ENCFF321QPN.bed.gz");
assert!(RegionSet::try_from(file_path).is_ok());
}

#[rstest]
#[ignore = "Failing but low priority"]
#[ignore = "Avoid BEDbase dependency in CI"]
fn test_open_from_bedbase() {
let bbid = String::from("6b2e163a1d4319d99bd465c6c78a9741");
let region_set = RegionSet::try_from(bbid);
Expand Down
42 changes: 26 additions & 16 deletions gtars-core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use std::str::FromStr;

use anyhow::{Context, Result};
use flate2::read::{GzDecoder, MultiGzDecoder};
#[cfg(feature = "http")]
use reqwest::blocking::Client;
use std::error::Error;
#[cfg(feature = "http")]
use ureq::{get, Error as UreqError};

use crate::models::region::Region;

Expand Down Expand Up @@ -133,27 +133,37 @@ pub fn get_dynamic_reader(path: &Path) -> Result<BufReader<Box<dyn Read>>> {
pub fn get_dynamic_reader_from_url(
url: &Path,
) -> Result<BufReader<Box<dyn std::io::Read>>, Box<dyn Error>> {
// Create an HTTP client and fetch the content
let mut url: String = url.to_str().unwrap().to_string();

let is_ftp: bool = url.starts_with("ftp");
let mut url_str = url
.to_str()
.ok_or_else(|| "URL path is not valid UTF-8")?
.to_string();

let is_ftp = url_str.starts_with("ftp://");
if is_ftp {
println!("ftp is not fully implemented. Bugs could appear");
url = url.replacen("ftp://", "http://", 1);
url_str = url_str.replacen("ftp://", "http://", 1);
}

let response = Client::new()
.get(&url)
.send()
.with_context(|| format!("Failed to fetch content from URL: {}", &url))?
.error_for_status()?
.bytes()?;
// Perform request
let response = match get(&url_str).call() {
Ok(resp) => resp,
Err(UreqError::StatusCode(code)) => {
return Err(format!("HTTP status {} when fetching {}", code, url_str).into())
}
Err(e) => return Err(format!("Request error when fetching {}: {}", url_str, e).into()),
};

// Read the entire HTTP response body into memory as a Vec<u8>
let mut bytes = Vec::new();
response
.into_body()
.into_reader()
.read_to_end(&mut bytes)
.map_err(|e| format!("Failed reading response body from {}: {}", url_str, e))?;

// Convert the response into a cursor for reading
let cursor = Cursor::new(response);
let cursor = Cursor::new(bytes);

let is_gzipped = url.ends_with(".gz");
let is_gzipped = url_str.ends_with(".gz");

let reader: Box<dyn std::io::Read> = match is_gzipped {
true => Box::new(GzDecoder::new(cursor)),
Expand Down
2 changes: 1 addition & 1 deletion gtars-python/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "gtars-py"
version = "0.5.2"
version = "0.5.3"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
4 changes: 2 additions & 2 deletions gtars/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "gtars"
version = "0.5.1"
version = "0.5.2"
edition = "2024"
description = "Performance critical tools for genomic interval analysis."
homepage = "https://github.com/databio/gtars"
Expand All @@ -12,7 +12,7 @@ categories = ["science::bioinformatics::genomics", "science::bioinformatics"]


[dependencies]
gtars-core = { path = "../gtars-core", optional = true, version="0.5.1", features = ["bigbed", "http"] }
gtars-core = { path = "../gtars-core", optional = true, version="0.5.3", features = ["bigbed"] }
gtars-tokenizers = { path = "../gtars-tokenizers", features = ["huggingface"], optional = true, version="0.5.1" }
gtars-io = { path = "../gtars-io", optional = true, version="0.5.0" }
gtars-refget = { path = "../gtars-refget", optional = true, version="0.5.0" }
Expand Down