From 4c9d57e46ff8462eccbb68f11442b03930f8b850 Mon Sep 17 00:00:00 2001 From: TroyHernandez Date: Sun, 2 Aug 2026 23:37:48 -0500 Subject: [PATCH] Tests: pin safetensors capability instead of probing the environment Windows R-devel failed the check on a test that passes here: FAILED: test_flux_staging.R<51> call| expect_equal(recommend("flux1", vram_gb = 16)$text_device, "cuda") diff| Expected 'cuda', got 'cpu' recommend() with st_caps = NULL probes the *installed* safetensors, so the fp8 tier only exists on a build that can read float8. This box has the dev build; Windows and CRAN have stock, where flux1 at 16 GB resolves to nf4 and its CPU encode. The assertion was environmental, not wrong. It now pins st_caps explicitly and asserts both directions -- fork caps give "cuda", stock caps give "cpu" for the same card. The fp8 round-trip blocks in four files had a related problem: each re-probed float8 support with its own tryCatch instead of asking .st_can_write(), so the guard and the code under test could disagree whenever options(diffuseR.st_caps) was set. Setting that override to simulate a stock CRAN machine sent them into the block and straight into the hard error the override exists to model. They now share one gate, which makes that simulation usable: options(diffuseR.st_read_caps = list(bfloat16 = TRUE, float8_e4m3fn = FALSE), diffuseR.st_caps = list(bfloat16 = FALSE, float8_e4m3fn = FALSE)) tinytest::run_test_dir("inst/tinytest") 1069 assertions pass under those settings (the fp8 blocks skip), 1097 with the dev build installed. That is the check that would have caught this before Windows did. Test-only, so no version bump. --- inst/tinytest/test_flux_staging.R | 30 ++++++++++++++++++++++------ inst/tinytest/test_fp8_ltx23.R | 11 +++------- inst/tinytest/test_quantize_flux.R | 13 +++++------- inst/tinytest/test_quantize_flux2.R | 11 +++------- inst/tinytest/test_quantize_zimage.R | 11 +++------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/inst/tinytest/test_flux_staging.R b/inst/tinytest/test_flux_staging.R index 6e7bbc0..192f082 100644 --- a/inst/tinytest/test_flux_staging.R +++ b/inst/tinytest/test_flux_staging.R @@ -47,12 +47,30 @@ expect_equal(diffuseR:::.pinned_set_gb("flux1", "bf16"), 34) # --- flux tier text_device: flux1 GPU-encodes only where T5 fits ------------------ # fp8/bf16 tiers (>=14 GB) onload T5; nf4 tiers keep CPU-fp32 encode. -expect_equal(recommend("flux1", vram_gb = 24)$text_device, "cuda") -expect_equal(recommend("flux1", vram_gb = 16)$text_device, "cuda") # fp8 tier -expect_equal(recommend("flux1", vram_gb = 10)$text_device, "cpu") # nf4 tier -expect_equal(recommend("flux1", vram_gb = 0)$text_device, "cpu") # cpu tier -# The small flux2/zimage encoder rides the GPU on every GPU tier. -expect_equal(recommend("flux2", vram_gb = 16)$text_device, "cuda") +# +# st_caps is pinned explicitly here. Left NULL, recommend() probes the +# *installed* safetensors, so the fp8 tier only exists on a machine whose +# build can read float8 -- which made this block pass on a dev box with +# the fork and fail on Windows R-devel, and would have failed on CRAN, +# where flux1 at 16 GB resolves to nf4 and its CPU encode instead. +st_fork <- list(bfloat16 = TRUE, float8_e4m3fn = TRUE) +st_cran <- list(bfloat16 = TRUE, float8_e4m3fn = FALSE) +expect_equal(recommend("flux1", vram_gb = 24, st_caps = st_fork)$text_device, + "cuda") +expect_equal(recommend("flux1", vram_gb = 16, st_caps = st_fork)$text_device, + "cuda") # fp8 tier +expect_equal(recommend("flux1", vram_gb = 16, st_caps = st_cran)$text_device, + "cpu") # same card, stock safetensors: nf4 tier +expect_equal(recommend("flux1", vram_gb = 10, st_caps = st_fork)$text_device, + "cpu") # nf4 tier +expect_equal(recommend("flux1", vram_gb = 0, st_caps = st_fork)$text_device, + "cpu") # cpu tier +# The small flux2/zimage encoder rides the GPU on every GPU tier, +# whichever safetensors is installed. +expect_equal(recommend("flux2", vram_gb = 16, st_caps = st_fork)$text_device, + "cuda") +expect_equal(recommend("flux2", vram_gb = 16, st_caps = st_cran)$text_device, + "cuda") # --- .flux_build_staging opt-out paths return NULL (no torch needed) -------------- diff --git a/inst/tinytest/test_fp8_ltx23.R b/inst/tinytest/test_fp8_ltx23.R index fb86506..936f275 100644 --- a/inst/tinytest/test_fp8_ltx23.R +++ b/inst/tinytest/test_fp8_ltx23.R @@ -8,14 +8,9 @@ if (!requireNamespace("safetensors", quietly = TRUE)) { exit_file("safetensors not installed") } # fp8 needs the F8-capable safetensors build -f8_ok <- tryCatch({ - x <- torch::torch_randn(2, 2)$to(dtype = torch::torch_float8_e4m3fn()) - tmp <- tempfile(fileext = ".safetensors") - safetensors::safe_save_file(list(w = x), tmp) - y <- safetensors::safe_load_file(tmp, framework = "torch") - unlink(tmp) - TRUE -}, error = function(e) FALSE) +# Same gate the quantizer uses, so the diffuseR.st_caps override +# reaches this guard too; a private probe would disagree with it. +f8_ok <- diffuseR:::.st_can_write("float8_e4m3fn") if (!f8_ok) exit_file("safetensors build lacks F8 support") library(diffuseR) diff --git a/inst/tinytest/test_quantize_flux.R b/inst/tinytest/test_quantize_flux.R index 03b8e02..32fe6a2 100644 --- a/inst/tinytest/test_quantize_flux.R +++ b/inst/tinytest/test_quantize_flux.R @@ -87,14 +87,11 @@ ltx23_release_dequant_buffers() # --- fp8 round trip (needs an F8-capable safetensors build) --------------------------- -f8_ok <- tryCatch({ - x <- torch::torch_randn(2, 2)$to(dtype = torch::torch_float8_e4m3fn()) - tmp <- tempfile(fileext = ".safetensors") - safetensors::safe_save_file(list(w = x), tmp) - y <- safetensors::safe_load_file(tmp, framework = "torch") - unlink(tmp) - TRUE -}, error = function(e) FALSE) +# Ask the same gate flux_quantize() asks, rather than re-probing here: a +# private probe can disagree with .st_can_write() whenever the +# diffuseR.st_caps override is set, and then this block runs only to hit +# the hard error the override was meant to simulate. +f8_ok <- diffuseR:::.st_can_write("float8_e4m3fn") if (f8_ok) { fp8_dir <- file.path(tempdir(), "flux-tiny-fp8") diff --git a/inst/tinytest/test_quantize_flux2.R b/inst/tinytest/test_quantize_flux2.R index 162f7e9..1a3c52d 100644 --- a/inst/tinytest/test_quantize_flux2.R +++ b/inst/tinytest/test_quantize_flux2.R @@ -78,14 +78,9 @@ ltx23_release_dequant_buffers() # --- fp8 round trips (streamed and resident) ------------------------------------------ -f8_ok <- tryCatch({ - x <- torch::torch_randn(2, 2)$to(dtype = torch::torch_float8_e4m3fn()) - tmp <- tempfile(fileext = ".safetensors") - safetensors::safe_save_file(list(w = x), tmp) - y <- safetensors::safe_load_file(tmp, framework = "torch") - unlink(tmp) - TRUE -}, error = function(e) FALSE) +# Same gate the quantizer uses, so the diffuseR.st_caps override +# reaches this guard too; a private probe would disagree with it. +f8_ok <- diffuseR:::.st_can_write("float8_e4m3fn") if (f8_ok) { fp8_dir <- file.path(tempdir(), "flux2-tiny-fp8") diff --git a/inst/tinytest/test_quantize_zimage.R b/inst/tinytest/test_quantize_zimage.R index 75b96de..e47b102 100644 --- a/inst/tinytest/test_quantize_zimage.R +++ b/inst/tinytest/test_quantize_zimage.R @@ -76,14 +76,9 @@ ltx23_release_dequant_buffers() # --- fp8 round trips (streamed and resident) ------------------------------------------ -f8_ok <- tryCatch({ - x <- torch::torch_randn(2, 2)$to(dtype = torch::torch_float8_e4m3fn()) - tmp <- tempfile(fileext = ".safetensors") - safetensors::safe_save_file(list(w = x), tmp) - y <- safetensors::safe_load_file(tmp, framework = "torch") - unlink(tmp) - TRUE -}, error = function(e) FALSE) +# Same gate the quantizer uses, so the diffuseR.st_caps override +# reaches this guard too; a private probe would disagree with it. +f8_ok <- diffuseR:::.st_can_write("float8_e4m3fn") if (f8_ok) { fp8_dir <- file.path(tempdir(), "zimage-tiny-fp8")