r-lib/withr

with_language() fails to reset the cache on Alpine Linux

bastistician opened this issue · 8 comments

withr/R/language.R

Lines 48 to 50 in 35301f6

# resets the cache. So if there's some OS/setup that this technique fails
# on, we might try bindtextdomain() instead or as well.
local_locale(c(LC_MESSAGES = ""), .local_envir = .local_envir)

Yes there is: musl-based Alpine Linux.
example("with_language") gives:

wth_ln> with_language("en", try(mean[[1]]))
Error in mean[[1]] : object of type 'closure' is not subsettable

wth_ln> with_language("fr", try(mean[[1]]))
Error in mean[[1]] : objet de type 'closure' non indiçable

wth_ln> with_language("es", try(mean[[1]]))
Error in mean[[1]] : objet de type 'closure' non indiçable

All subsequent invocations of that error message stick to French.

R CMD checking withr fails for me from

expect_error(with_language("es", mean[[1]]), "no es subconjunto")

due to this issue.

In R >= 4.2.0, bindtextdomain(NULL) could be used to flush the cache, as in Sys.setLanguage(). This works on Alpine Linux:

> Sys.setLanguage("en"); try(mean[[1]])
Error in mean[[1]] : object of type 'closure' is not subsettable
> Sys.setLanguage("fr"); try(mean[[1]])
Error in mean[[1]] : objet de type 'closure' non indiçable
> Sys.setLanguage("es"); try(mean[[1]])
Error in mean[[1]] : objeto de tipo 'closure' no es subconjunto
sessionInfo()
R Under development (unstable) (2023-02-09 r83794)
Platform: x86_64-pc-linux-musl (64-bit)
Running under: Alpine Linux v3.17

Matrix products: default
BLAS:   /home/smeyer/QA/R-83794/build/lib/libRblas.so 
LAPACK: /home/smeyer/QA/R-83794/build/lib/libRlapack.so;  LAPACK version 3.11.0

locale:
[1] C.UTF-8 C       C       C       C       C      

time zone: Europe/Berlin
tzcode source: internal
maelle commented

@KevCaz noticed this bug in my post about potools

I observe the same behavior as @bastistician (on Ubuntu)

library("withr")
with_language("en", try(mean[[1]]))
#> Error in mean[[1]] : object of type 'closure' is not subsettable
with_language("fr", try(mean[[1]]))
#> Error in mean[[1]] : objet de type 'closure' non indiçable
with_language("es", try(mean[[1]]))
#> Error in mean[[1]] : objeto de tipo 'closure' no es subconjunto
try(mean[[1]])
#> Error in mean[[1]] : objeto de tipo 'closure' no es subconjunto

with_language("fr", try(mean[[1]]))
#> Error in mean[[1]] : objet de type 'closure' non indiçable
try(mean[[1]])
#> Error in mean[[1]] : objet de type 'closure' non indiçable

Created on 2023-10-09 with reprex v2.0.2

I had to also set LANG / LC_ALL in my unit tests: 08619ef. Does that fix it for you @maelle?

@hadley I wonder if we should try and set it automatically if not set already? We'd use some country as default for each language. To override, the user could supply a length-2 character vector. It might be tricky to have the mapping be both comprehensive and cross-platform.

maelle commented

I had to change the locale code to make your example work on my machine but that seems to be expected for different OS. 😅

It seems to work!

with_lang <- function(lc, language, expr) {
  withr::local_envvar(c(LC_ALL = lc))
  withr::local_language(language)
  expr
}

with_lang("fr_FR.UTF-8", "fr", try(mean[[1]]))
#> Error in mean[[1]] : objet de type 'closure' non indiçable
try(mean[[1]])
#> Error in mean[[1]] : object of type 'closure' is not subsettable

Created on 2023-10-09 with reprex v2.0.2

hadley commented

@lionel- do we need to set LC_ALL to the matching language, or can we just set it to something other than C? Should we be using Sys.setLanguage() in versions of R that provide it?

After some reading including https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=931456 and https://bugs.r-project.org/show_bug.cgi?id=18055 here is my understanding of things:

  • LANGUAGE doesn't do anything when LC_ALL is set to C (see https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html) which is why I had to set LC_ALL in unit tests to override platforms where it is set to C (e.g. one of Kurt's Debian machines IIRC). This is an entirely separate problem.

  • There are cache invalidation bugs in GNU libc that require workarounds to force a reset. Setting LC_ALL / LANG envvars, like I did for the aforementioned issue, is one of them but should not be necessary here. We can use other workarounds, for instance the one Hadley experimented with in #183, or the one Martin implemented in Sys.setLanguage() with bindtextdomain(NULL). For now I think I'd rather use Hadley's approach until we can drop support for R < 4.2.0, since Martin's workaround won't work on these older R versions.

Thanks! I can confirm that applying Commit a57401a (#183) on the current CRAN version 2.5.2 resolves the check failure for me: "Status: OK". 👍

Thanks for checking!