diff --git a/Makefile b/Makefile index c65ef3b9..2bbfc149 100644 --- a/Makefile +++ b/Makefile @@ -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: diff --git a/gtars-bbcache/Cargo.toml b/gtars-bbcache/Cargo.toml index 8911d1a7..5050d6b3 100644 --- a/gtars-bbcache/Cargo.toml +++ b/gtars-bbcache/Cargo.toml @@ -1,6 +1,6 @@ [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" @@ -8,7 +8,7 @@ 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" @@ -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" diff --git a/gtars-bbcache/src/client.rs b/gtars-bbcache/src/client.rs index f85e3112..da4595a5 100644 --- a/gtars-bbcache/src/client.rs +++ b/gtars-bbcache/src/client.rs @@ -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}; @@ -367,7 +367,12 @@ impl BBClient { fn download_bedset_data(&self, bedset_id: &str) -> Result> { 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() + .map_err(|e| anyhow!("Failed to read response body for {}: {}", bedset_url, e))?; let json: serde_json::Value = serde_json::from_str(&response)?; diff --git a/gtars-core/Cargo.toml b/gtars-core/Cargo.toml index c71cccc4..16cb6a37 100644 --- a/gtars-core/Cargo.toml +++ b/gtars-core/Cargo.toml @@ -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" @@ -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 } @@ -24,4 +24,4 @@ tempfile = "3.21.0" [features] default = [] bigbed = ["dep:bigtools"] -http = ["dep:reqwest"] \ No newline at end of file +http = ["dep:ureq"] \ No newline at end of file diff --git a/gtars-core/src/models/region_set.rs b/gtars-core/src/models/region_set.rs index d7b5ab07..225d6ace 100644 --- a/gtars-core/src/models/region_set.rs +++ b/gtars-core/src/models/region_set.rs @@ -183,7 +183,7 @@ impl TryFrom for RegionSet { type Error = anyhow::Error; fn try_from(value: String) -> Result { - println!("Converting String to Path: {}", value); + // println!("Converting String to Path: {}", value); RegionSet::try_from(Path::new(&value)) } } @@ -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); diff --git a/gtars-core/src/utils.rs b/gtars-core/src/utils.rs index ed26d524..feba2c19 100644 --- a/gtars-core/src/utils.rs +++ b/gtars-core/src/utils.rs @@ -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; @@ -133,27 +133,37 @@ pub fn get_dynamic_reader(path: &Path) -> Result>> { pub fn get_dynamic_reader_from_url( url: &Path, ) -> Result>, Box> { - // 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 + 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 = match is_gzipped { true => Box::new(GzDecoder::new(cursor)), diff --git a/gtars-python/Cargo.toml b/gtars-python/Cargo.toml index dc0eeacf..517b260c 100644 --- a/gtars-python/Cargo.toml +++ b/gtars-python/Cargo.toml @@ -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 diff --git a/gtars/Cargo.toml b/gtars/Cargo.toml index 5dbda9d7..206077a6 100644 --- a/gtars/Cargo.toml +++ b/gtars/Cargo.toml @@ -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" @@ -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" }