R/AAAA.R

Defines functions .inform_missing_module .find_python .onAttach .onLoad .has_python3 .loadModules .gd_version_ge gd_ee_version earthengine gd_version geedim gd_python_envname

Documented in earthengine gd_ee_version gd_version geedim

gd <- NULL
collections_module <- NULL
google_auth_module <- NULL

gd_python_envname <- function(envname = "") {
  if (!missing(envname)) {
    reticulate::use_virtualenv(envname, required = FALSE)
    en <- envname
  } else if (is.null(envname)) {
    en <- ""
  } else {
    en <- getOption("rgeedim.python.envname",
                    default = Sys.getenv("R_RGEEDIM_PYTHON_ENVNAME", 
                                         unset = "r-rgeedim"))
  }
  en
}

#' `Module(geedim)` - Get `geedim` Module Instance
#'
#' Gets the `geedim` module instance in use by the package in current **R**/`reticulate` session.
#'
#' @export
geedim <- function() {
  gd
}

#' `gd_version()`: Gets the `geedim` version
#' @rdname geedim
#' @return character. Version Number.
#' @export
#' @importFrom reticulate py_eval
gd_version <- function() {
  try(reticulate::py_eval("version('geedim')"), silent = TRUE)
}

#' Get Earth Engine `Module(earthengine-api)` Instance
#'
#' Gets the `earthengine-api` module instance in use by `geedim` package in current session.
#'
#' @export
earthengine <- function() {
  gd$utils$ee
}

#' @description `gd_ee_version()` Gets the `earthengine-api` version using `importlib.metadata.version()`
#'
#' @rdname earthengine
#' @return character. Version Number.
#' @export
#' @importFrom reticulate py_eval
gd_ee_version <- function() {
  try(reticulate::py_eval("version('earthengine-api')"), silent = TRUE)
}

.gd_version_ge <- function(ver) {
  res <- gd_version()
  if (inherits(res, "try-error")) {
    # second attempt with geedim.__version__ if module already loaded
    res <- try(reticulate::py_eval("geedim.__version__"), silent = TRUE)
  }
  if (inherits(res, "try-error")) return(FALSE)
  return(numeric_version(res) >= numeric_version(ver))
}

#' @importFrom reticulate import
#' @importFrom reticulate py_run_string
.loadModules <-  function() {
  # TODO: store modules in package environment not global variables?
  envname <- gd_python_envname()
  if (reticulate::virtualenv_exists(envname)) {
    reticulate::use_virtualenv(envname, required = FALSE)
  } else if (reticulate::condaenv_exists(envname)) {
    reticulate::use_condaenv(envname, required = FALSE)
  }
  
  suppressWarnings({
    if (is.null(collections_module)) {
      try(collections_module <<- reticulate::import('collections', delay_load = TRUE), silent = TRUE)
    }
  
    if (is.null(gd)) {
      try(gd <<- reticulate::import("geedim", delay_load = TRUE), silent = TRUE)
    }

    if (is.null(google_auth_module)) {
      try(google_auth_module <<- reticulate::import("google.auth", delay_load = TRUE), silent = TRUE)
    }
  
    # note: requires Python >= 3.8; but is not essential for functioning of package
    try(reticulate::py_run_string("from importlib.metadata import version"), silent = TRUE)
  })
  !is.null(gd)
}

#' @importFrom reticulate py_discover_config
.has_python3 <- function() {
  # get reticulate python information
  # NB: reticulate::py_config() calls configure_environment() etc.
  #     .:. use py_discover_config()
  x <- try(suppressWarnings(reticulate::py_discover_config(use_environment = gd_python_envname())), silent = TRUE)

  # need python 3 for reticulate
  # need python 3.6+ for geedim
  if (length(x) > 0 && !inherits(x, 'try-error')) {
    if (numeric_version(x$version) >= "3.6") {
      return(TRUE)
    } else if (numeric_version(x$version) >= "3.0") {
      # message about geedim dependency? not on load.
      return(FALSE)
    }
  }
  FALSE
}

#' @importFrom reticulate configure_environment
.onLoad <- function(libname, pkgname) {
  if (packageVersion("reticulate") >= "1.41.0") {
    reticulate::py_require(c("earthengine-api", "geedim", "google-auth"))
  }
  .loadModules()
}

#' @importFrom utils packageVersion
.onAttach <- function(libname, pkgname) {
  # Only attempt to fetch versions if Python is already initialized or we are in a session
  # where a long timeout for discovery/auto-install is acceptable (interactive/CI).
  # This prevents 70s+ delays on CRAN checks when geedim is missing.
  do_check <- reticulate::py_available() || 
              interactive() || 
              isTRUE(as.logical(Sys.getenv("NOT_CRAN")))
  
  gdv <- gev <- "<Not Initialized>"
  if (do_check) {
    gdv <- suppressWarnings(gd_version())
    gev <- suppressWarnings(gd_ee_version())
    if (inherits(gdv, 'try-error'))
      gdv <- "<Not Found>"
    if (inherits(gev, 'try-error'))
      gev <- "<Not Found>"
  }
  
  packageStartupMessage(
    "rgeedim v",
    utils::packageVersion("rgeedim"),
    " -- using geedim ",
    gdv,
    " w/ earthengine-api ",
    gev
  )
}

.find_python <- function() {
  # find python
  py_path <- Sys.which("python")
  if (nchar(py_path) == 0) {
    py_path <- Sys.which("python3")
  }
  py_path
}

.inform_missing_module <- function(object, module_name = "geedim", quiet = FALSE) {
  
  check_failed <- FALSE
  if (is.null(object) || inherits(object, 'try-error')) {
    check_failed <- TRUE
  } else {
    # Verify we can access the module (triggers delay load)
    # Using py_module_available is safer than accessing attributes on the proxy
    if (!reticulate::py_module_available(module_name)) {
      check_failed <- TRUE
    }
  }

  if (check_failed) {
    if (quiet) {
      return(invisible(structure(list(message = sprintf("Failed to load '%s' Python module", module_name)), class = "try-error")))
    }
    stop(sprintf("Failed to load '%s' Python module. Check reticulate environment settings and ensure '%s' module is installed. If prompted to set up a default reticulate environment, choose 'Yes'. See `gd_install()` for more details.", module_name, module_name), call. = FALSE)
  }
}

Try the rgeedim package in your browser

Any scripts or data that you put into this service are public.

rgeedim documentation built on Feb. 2, 2026, 9:06 a.m.