Skip to content

Commit

Permalink
Added cedta.pkgEvalsUserCode and only any eval() is affected not othe…
Browse files Browse the repository at this point in the history
…r code in the package itself (e.g. knitr::kable). Closes #809.
  • Loading branch information
mattdowle committed Oct 20, 2014
1 parent a303a94 commit 605b44d
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 15 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Author: M Dowle, T Short, S Lianoglou, A Srinivasan with contributions from R Sa
Maintainer: Matt Dowle <mdowle@mdowle.plus.com>
Depends: R (>= 2.14.0)
Imports: methods, chron
Suggests: ggplot2 (>= 0.9.0), plyr, reshape, reshape2, testthat (>= 0.4), hexbin, fastmatch, nlme, xts, bit64, gdata, GenomicRanges, caret
Suggests: ggplot2 (>= 0.9.0), plyr, reshape, reshape2, testthat (>= 0.4), hexbin, fastmatch, nlme, xts, bit64, gdata, GenomicRanges, caret, knitr
Description: Fast aggregation of large data (e.g. 100GB in RAM), fast ordered joins, fast add/modify/delete of columns by group using no copies at all, list columns and a fast file reader (fread). Offers a natural and flexible syntax, for faster development.
License: GPL (>= 2)
URL: https://github.com/Rdatatable/data.table/wiki
Expand Down
26 changes: 19 additions & 7 deletions R/cedta.R
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@

cedta.override = c("gWidgetsWWW","statET","FastRWeb","slidify","rmarkdown","knitr")
# These packages tend to be ones that run user code in their own environment and thus do not
# themselves Depend or Import data.table.
cedta.override = NULL # If no need arises, will deprecate.

cedta.pkgEvalsUserCode = c("gWidgetsWWW","statET","FastRWeb","slidify","rmarkdown","knitr")
# These packages run user code in their own environment and thus do not
# themselves Depend or Import data.table. knitr's eval is passed envir=globalenv() so doesn't
# need to be listed here currently, but we include it in case it decides to change that.
# The others create their own environment to eval in.
# The packages might use data.frame syntax elsewhere in their package code so we just want
# the eval (only) of user code to be data.table-aware.

# If a new package needs to be added to this vector, a user may add to it using :
# assignInNamespace("cedta.override", c(data.table:::cedta.override,"<nsname>"), "data.table")
# assignInNamespace("cedta.pkgEvalsUserCode", c(data.table:::cedta.pkgEvalsUserCode,"<nsname>"), "data.table")
# But please let us know so we can add the package to this vector in the package upstream, so other
# users don't have to tread the same path. Then you can remove your assignInNamepace() call.
# Or, packages like those above can set a variable in their namespace

# Packages may also set a variable in their namespace :
# .datatable.aware = TRUE
# which achieves the same thing. Either way.
# which makes them data.table-aware optionally and possibly variably.
# http://stackoverflow.com/a/13131555/403310

cedta = function(n=2L) {
# Calling Environment Data Table Aware
te = topenv(parent.frame(n))
if (!isNamespace(te)) return(TRUE) # e.g. DT queries in .GlobalEnv
if (!isNamespace(te)) {
# e.g. DT queries at the prompt (.GlobalEnv) and knitr's eval(,envir=globalenv()) but not DF[...] inside knitr::kable v1.6
return(TRUE)
}
nsname = getNamespaceName(te)
ans = nsname == "data.table" ||
"data.table" %chin% names(getNamespaceImports(te)) ||
"data.table" %chin% tryCatch(get(".Depends",paste("package",nsname,sep=":"),inherits=FALSE),error=function(e)NULL) ||
(nsname == "utils" && exists("debugger.look",parent.frame(n+1L))) ||
(nsname == "base" && all(c("FUN", "X") %in% ls(parent.frame(n))) ) || # lapply
(nsname %chin% cedta.pkgEvalsUserCode && any(sapply(sys.calls(), "[[", 1L)=="eval")) ||
nsname %chin% cedta.override ||
identical(TRUE, tryCatch(get(".datatable.aware",asNamespace(nsname),inherits=FALSE),error=function(e)NULL))
if (!ans && getOption("datatable.verbose"))
Expand Down
5 changes: 3 additions & 2 deletions R/data.table.R
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,13 @@ print.data.table = function(x,
{
if (.global$print != "" &&
length(SYS<-last(sys.calls()))>=2 &&
typeof(SYS[[2]]) == "list" && # auto-printing; e.g. not explicit print. When explicit print this is not list; e.g. symbol or language
typeof(SYS[[2]]) %chin% c("list","promise") && # auto-printing; e.g. not explicit print. "promise" to future proof
address(x) == .global$print ) {
# := in [.data.table sets print=address(x) to suppress next autoprint at the console. See FAQ 2.22 and README item in v1.9.5
# Other options investigated (could revisit): Cstack_info(), .Last.value gets set first before autoprint, history(), sys.status(),
# topenv(), inspecting next statement in caller, using clock() at C level to timeout suppression after some number of cycles
# The issue is distinguishing "> DT" (after a previous := in a function) from "> DT[,foo:=1]". To print.data.table() there is no difference.
# The issue is distinguishing "> DT" (after a previous := in a function) from "> DT[,foo:=1]". To print.data.table() there
# is no difference.
.global$print = ""
return(invisible())

Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@
12. Compatibility with big endian machines (e.g., SPARC and PowerPC) is restored. Most Windows, Linux and Mac systems are little endian; type `.Platform$endian` to confirm. Thanks to Gerhard Nachtmann for reporting and the [QEMU project](http://qemu.org/) for their PowerPC emulator.

13. `DT[, LHS := RHS]` with RHS is of the form `eval(parse(text = foo[1]))` referring to columns in `DT` is now handled properly. Closes [#880](https://github.com/Rdatatable/data.table/issues/880). Thanks to tyner.

14. `knitr::kable()` works again without needing to upgrade from knitr v1.6 to v1.7. Packages which evaluate user code and don't wish to import data.table need to be added to `data.table:::cedta.pkgEvalsUserCode` and now only the `eval` part is made data.table-aware (the rest of such package's code is left data.table-unaware). `data.table:::cedta.override` is now empty and will be deprecated if no need for it arises.

14. `subset` handles extracting duplicate columns in consistency with data.table's rule - if a column name is duplicated, then accessing that column using column number should return that column, whereas accessing by column name (due to ambiguity) will always extract the first column. Closes [#891](https://github.com/Rdatatable/data.table/issues/891). Thanks to @jjzz.
15. `subset` handles extracting duplicate columns in consistency with data.table's rule - if a column name is duplicated, then accessing that column using column number should return that column, whereas accessing by column name (due to ambiguity) will always extract the first column. Closes [#891](https://github.com/Rdatatable/data.table/issues/891). Thanks to @jjzz.

15. `rbindlist` handles combining levels of data.tables with both ordered and unordered factor columns properly. Closes [#899](https://github.com/Rdatatable/data.table/issues/899). Thanks to @ChristK.
16. `rbindlist` handles combining levels of data.tables with both ordered and unordered factor columns properly. Closes [#899](https://github.com/Rdatatable/data.table/issues/899). Thanks to @ChristK.

#### NOTES

Expand Down
14 changes: 11 additions & 3 deletions inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ if (!exists("test.data.table",.GlobalEnv,inherits=FALSE)) {
require(gdata)
require(GenomicRanges)
require(caret)
require(knitr)
# reshape2 ahead of reshape ...
try(detach(package:reshape2),silent=TRUE)
try(detach(package:reshape),silent=TRUE)
Expand Down Expand Up @@ -5434,6 +5435,13 @@ for (i in seq_along(DT)) {
test(test_no, ans1, ans2)
0L
})

# That data.table-unaware code in packages like knitr still work
if ("package:knitr" %in% search()) {
DT = data.table(x=1, y=2)
test(1395, kable(DT), output="x.*y.*1.*2") # kable in knitr v1.6 calls DF[...] syntax
} else {
cat("Test 1395 not run. If required call library(knitr) first.\n")
}

##########################
Expand Down Expand Up @@ -5465,14 +5473,14 @@ for (i in seq_along(DT)) {
##########################
options(warn=0)
options(oldbwb) # set at top of this file
plat = paste(", endian=",.Platform$endian,", ","sizeof(long double)==",.Machine$sizeof.longdouble,sep="")
plat = paste("endian=",.Platform$endian,", sizeof(long double)==",.Machine$sizeof.longdouble,sep="")
if (nfail > 0) {
if (nfail>1) {s1="s";s2="s: "} else {s1="";s2=" "}
cat("\r")
stop(nfail," error",s1," out of ",ntest, " (lastID=",lastnum, plat, ") in inst/tests/tests.Rraw on ",date(),". Search tests.Rraw for test number",s2,paste(whichfail,collapse=", "),".")
stop(nfail," error",s1," out of ",ntest, " (lastID=",lastnum,", ",plat, ") in inst/tests/tests.Rraw on ",date(),". Search tests.Rraw for test number",s2,paste(whichfail,collapse=", "),".")
# important to stop() here, so that 'R CMD check' fails
}
cat("\rAll ",ntest," tests (lastID=",lastnum, plat, ") in inst/tests/tests.Rraw completed ok in ",timetaken(started.at)," on ",date(),"\n",sep="")
cat("\rAll ",ntest," tests (lastID=",lastnum,") in inst/tests/tests.Rraw completed ok in ",timetaken(started.at)," on ",date()," (",plat,")\n",sep="")
# Reporting lastnum rather than ntest makes it easier to check user has the latest version, assuming
# each release or patch has extra tests.
# date() is included so we can tell when CRAN checks were run (in particular if they have been rerun since
Expand Down

0 comments on commit 605b44d

Please sign in to comment.