fix(data-io): bind lazy datasets into the namespace at load - #775
Open
lbm364dl wants to merge 1 commit into
Open
fix(data-io): bind lazy datasets into the namespace at load#775lbm364dl wants to merge 1 commit into
lbm364dl wants to merge 1 commit into
Conversation
With `LazyData: true` the shipped datasets are lazy-loaded into the namespace's `.__NAMESPACE__.$lazydata` environment, which `library(whep)` puts on the search path but which is not in the namespace itself. Package code is evaluated in the namespace, whose parents are imports -> base -> globalenv, so a bare reference to `polities` or `polity_area_crosswalk` only resolved through the search path -- i.e. only when the package was attached. `whep::f()` from a script without `library(whep)` aborted with `object 'polities' not found`, and 55 of the 56 datasets are referenced by bare name somewhere in `R/`. `.onLoad()` now copies every lazydata name that the namespace does not already define into the namespace with `delayedAssign()`, so the bindings stay promises and the data is still loaded on first use only. Existing namespace objects are never shadowed, and `whep::<dataset>` keeps returning the same object. Nothing caught this because `tests/testthat.R` attaches the package, examples run attached under `R CMD check`, and `pkgload::load_all()` puts the datasets in the namespace directly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
Confirmed on
origin/mainwith a normally installed package (R CMD INSTALLinto a temp lib, fresh
Rscript --vanilla, nolibrary(whep)):Mechanism, exactly as diagnosed in #641: with
LazyData: true,loadNamespace()lazy-loads
data/Rdata.rdbintons$.__NAMESPACE__.$lazydata, not into thenamespace. Package code is evaluated in the namespace, whose parents are
imports → base → globalenv, so a bare
politiescan only be found via thesearch path — which holds the datasets only once
library(whep)has attachedthe package env.
whep::politiesworks because::falls back to the lazydataenvironment. All 100 lazy-loaded objects (56 topics) are invisible to package
code in the loaded-but-not-attached state, and 55 of the 56 datasets are
referenced by bare name in
R/.What changed
New
R/zzz.R(25 lines, no call sites touched — options 1 and 3 in the issuewould have rewritten ~667 references across 67 files):
.onLoad()binds each lazydata name that the namespace does not alreadydefine into the namespace with
delayedAssign(). The namespace is stillunlocked while
.onLoad()runs, so this is a legal assignment; sealingafterwards just locks the promises.
rlang::env_binding_are_lazy(asNamespace("whep"), c("polities", "biomass_coefs"))→
TRUE TRUEright afterloadNamespace("whep"), so nothing is eagerlyloaded and memory behaviour is unchanged.
setdiffagainstls(ns)),and
identical(whep::polities, get("polities", asNamespace("whep")))isTRUE.library(whep)andpkgload::load_all()are unaffected (underload_all()the datasets are already in the namespace, so the binder is a no-op).
Classification: mechanical — a packaging/visibility fix. No published value
changes.
Verification
tests/testthat/test_zzz.R: four unit tests of the binder (binds, keeps lazy,never shadows, no-op without a lazydata env) plus an invariant that every object
in the package's lazydata environment is reachable from the namespace — the
guard that would have caught this.
Before the fix, running the new test file against the installed
(unpatched) package, i.e. the
R CMD checkstate:After the fix, same installed-package run:
and the issue's reproduction script:
Also run:
devtools::test(filter="zzz")→FAIL 0 | PASS 9devtools::test(filter="polities|gapfilling|datasets")→FAIL 0 | SKIP 1 | PASS 1080rcmdcheck::rcmdcheck(build_args="--no-build-vignettes", args=c("--no-tests","--ignore-vignettes"))→
0 errors | 0 warnings | 0 notes(with_R_CHECK_FORCE_SUGGESTS_=false;archiveandRSQLiteare not installed on this machine)air format .,lintr::lint()on both changed files → no lintsman/,_pkgdown.ymlandutils::globalVariables()are untouched.Closes #641.
🤖 Generated with Claude Code