Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Completes coverage of all .R files #3761

Merged
merged 8 commits into from
Aug 12, 2019
Merged

Completes coverage of all .R files #3761

merged 8 commits into from
Aug 12, 2019

Conversation

MichaelChirico
Copy link
Member

@MichaelChirico MichaelChirico commented Aug 11, 2019

Closes #3758 too.

Please see also inline notes

R/bmerge.R Outdated
@@ -57,7 +57,7 @@ bmerge = function(i, x, icols, xcols, roll, rollends, nomatch, mult, ops, verbos
}
}
if (xclass == iclass) {
if (verbose) cat("i.",names(i)[ic],"has same type (",xclass,") as x.",names(x)[xc],". No coercion needed.\n", sep="")
if (verbose) cat("i.", names(i)[ic], " has same type (", xclass, ") as x.", names(x)[xc], ". No coercion needed.\n", sep="")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mainly missing a space, noticed in the verbose output for 2074.18

tt = grep("^eval|^[^[:alpha:]. ]",byvars,invert=TRUE,value=TRUE)
if (length(tt)) tt = tt[1L] else all.vars(bysubl[[jj+1L]])[1L]
# take the first variable that is (1) not eval (#3758) and (2) starts with a character that can't start a variable name
tt = grep("^eval$|^[^[:alpha:]. ]", byvars, invert=TRUE, value=TRUE)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simple fix for #3758 -- add ending anchor $ to the regex for eval

# take the first variable that is (1) not eval (#3758) and (2) starts with a character that can't start a variable name
tt = grep("^eval$|^[^[:alpha:]. ]", byvars, invert=TRUE, value=TRUE)
# byvars but exclude functions or `0`+`1` becomes `+`
tt = if (length(tt)) tt[1L] else all.vars(bysubl[[jj+1L]])[1L]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previous code I believe was doing nothing in the else case, so I'm not 100% sure of the intended behavior but I believe this is it.

@@ -1087,9 +1089,9 @@ replace_order = function(isub, verbose, env) {
if (is.list(k)) {
origj = j = if (name[[1L]] == "$") as.character(name[[3L]]) else eval(name[[3L]], parent.frame(), parent.frame())
if (is.character(j)) {
if (length(j)!=1L) stop("L[[i]][,:=] syntax only valid when i is length 1, but it's length %d",length(j))
if (length(j)!=1L) stop("Cannot assign to an under-allocated recursively indexed list -- L[[i]][,:=] syntax is only valid when i is length 1, but it's length ", length(j))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite the obscure error. Especially because the first code works while the second produces this error:

opt = options(datatable.alloccol=1L)
l = list(foo = list(bar = data.table(a = 1:3, b = 4:6)))
l$foo$bar[ , (letters) := 16:18]
l = list(foo = list(bar = data.table(a = 1:3, b = 4:6)))
l[[c('foo', 'bar')]][ , (letters) := 16:18]
options(opt)

j = match(j, names(k))
if (is.na(j)) stop("Item '",origj,"' not found in names of list")
if (is.na(j)) stop("Internal error -- item '", origj, "' not found in names of list") # nocov
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see a way for this to be triggered, so marking it as internal

@@ -1118,7 +1120,7 @@ replace_order = function(isub, verbose, env) {
xcolsAns = seq_along(ansvars)
icols = icolsAns = integer()
} else {
if (!length(leftcols)) stop("column(s) not found: ", paste(ansvars[wna],collapse=", "))
if (!length(leftcols)) stop("Internal error -- column(s) not found: ", paste(ansvars[wna],collapse=", ")) # nocov
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto above. AFAICT things that might trigger this are caught much earlier than here.

@codecov
Copy link

codecov bot commented Aug 11, 2019

Codecov Report

Merging #3761 into master will increase coverage by 0.58%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3761      +/-   ##
==========================================
+ Coverage   98.83%   99.41%   +0.58%     
==========================================
  Files          70       70              
  Lines       13228    13204      -24     
==========================================
+ Hits        13074    13127      +53     
+ Misses        154       77      -77
Impacted Files Coverage Δ
R/setops.R 100% <ø> (+0.52%) ⬆️
R/IDateTime.R 100% <ø> (+1.24%) ⬆️
src/fread.c 99.44% <ø> (+0.94%) ⬆️
R/print.data.table.R 100% <100%> (+4.95%) ⬆️
R/transpose.R 100% <100%> (ø) ⬆️
R/data.table.R 100% <100%> (+2.16%) ⬆️
src/bmerge.c 100% <100%> (+1.74%) ⬆️
R/groupingsets.R 100% <100%> (+3.57%) ⬆️
R/bmerge.R 100% <100%> (ø) ⬆️
... and 11 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 30a4fcd...8c1fe1b. Read the comment docs.

@@ -1294,7 +1296,7 @@ replace_order = function(isub, verbose, env) {
identical(irows, integer(0L)) && !bynull,
length(irows) && !anyNA(irows) && all(irows==0L) ## anyNA() because all() returns NA (not FALSE) when irows is all-NA. TODO: any way to not check all 'irows' values?
))
if (is.atomic(jval)) jval = jval[0L] else jval = lapply(jval, `[`, 0L)
jval = lapply(jval, `[`, 0L)
Copy link
Member Author

@MichaelChirico MichaelChirico Aug 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe is.atomic(jval) is possible here.

Just above you can see this branch enters with either is.list(jval) or !missingby:

https://github.com/Rdatatable/data.table/pull/3761/files#diff-650e4a11ed4384f8e560a6ebfff4ff53L1287

if ((is.call(jsub) && is.list(jval) && jsub[[1L]] != "get" && !is.object(jval)) || !missingby)

Obviously is.atomic(jval) is impossible in the first case. You have to scroll a bit further up but I think the second case is also impossible:

https://github.com/Rdatatable/data.table/pull/3761/files#diff-650e4a11ed4384f8e560a6ebfff4ff53L1168

if (missingby || bynull || (!byjoin && !length(byval)))

So we've either got bynull or (!byjoin && !length(byval)). But I'm not sure how length(byval) can be 0 but bynull is FALSE -- e.g. by = integer() would have byval = list(integer = integer()), so it's already en-listed.

@@ -1884,7 +1886,7 @@ as.matrix.data.table = function(x, rownames=NULL, rownames.value=NULL, ...) {
non.numeric = non.atomic = FALSE
all.logical = TRUE
for (j in seq_len(p)) {
if (is.ff(X[[j]])) X[[j]] = X[[j]][] # to bring the ff into memory, since we need to create a matrix in memory
if (is.ff(X[[j]])) X[[j]] = X[[j]][] # nocov to bring the ff into memory, since we need to create a matrix in memory
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't have ff in Suggests, so nocov. We have is.ff as a simple wrapper, so technically we could construct some object and force ff class to it & test but that's not really a test of what this branch is supposed to do. So nocov unless we want to add ff to Suggests, or if you think we should add ff to the test packages.

@@ -2880,7 +2882,7 @@ isReallyReal = function(x) {
## redirect to normal DT[x == TRUE]
stub = call("==", as.symbol(col), TRUE)
}
if (length(stub[[1L]]) != 1) return(NULL) ## Whatever it is, definitely not one of the valid operators
if (length(stub[[1L]]) != 1) return(NULL) # nocov Whatever it is, definitely not one of the valid operators
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see a way to reach this branch and the comment suggests it's there as an internal default, could you confirm @MarkusBonsch?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are completely right.

@@ -2902,7 +2904,6 @@ isReallyReal = function(x) {
# the mode() checks also deals with NULL since mode(NULL)=="NULL" and causes this return, as one CRAN package (eplusr 0.9.1) relies on
return(NULL)
}
if(is.character(x[[col]]) && !operator %chin% c("==", "%in%", "%chin%")) return(NULL) ## base R allows for non-equi operators on character columns, but these can't be optimized.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -2998,7 +2999,6 @@ isReallyReal = function(x) {
pat = paste0("(", ops, ")", collapse="|")
if (is.call(onsub) && onsub[[1L]] == "eval") {
onsub = eval(onsub[[2L]], parent.frame(2L), parent.frame(2L))
if (is.call(onsub) && onsub[[1L]] == "eval") { onsub = onsub[[2L]] }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The eval will eliminate any level of nested eval/quote already, so I don't think this branch is possible; see:

DT <- data.table(id = 1:3, `counts(a>=0)` = 1:3, sameName = 1:3)
i <- data.table(idi = 1:3, `  weirdName>=` = 1:3, sameName = 1:3)
DT[i, on = eval(eval(quote(eval("id<=idi"))))]

After eval onsub becomes id<=idi

@MichaelChirico
Copy link
Member Author

Once merged we'll be over 99% coverage! Mission accomplished 😎

R/data.table.R Outdated Show resolved Hide resolved
@MichaelChirico MichaelChirico changed the title Closes #3758 and completes coverage of data.table.R Closes #3758 and completes coverage of all files in R/ Aug 11, 2019
@@ -87,8 +87,9 @@ round.IDate = function (x, digits=c("weeks", "months", "quarters", "years"), ...
`+.IDate` = function (e1, e2) {
if (nargs() == 1L)
return(e1)
# TODO: investigate Ops.IDate method a la Ops.difftime
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted in ?Ops

The classes of both arguments are considered in dispatching any member of this group. For each argument its vector of classes is examined to see if there is a matching specific (preferred) or Ops method. If a method is found for just one argument or the same method is found for both, it is used. If different methods are found, there is a warning about ‘incompatible methods’: in that case or if no method is found for either argument the internal method is used.

Hence we can't really reach this branch since the incompatible methods barrier is hit first.

R/last.R Outdated
@@ -9,14 +9,16 @@ last = function(x, ...) {
if (!length(x)) return(x) else return(x[[length(x)]]) # for vectors, [[ works like [
} else if (is.data.frame(x)) return(x[NROW(x),])
}
# nocov start
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw the if branches covered in first but not last (despite apparently neither actually being hit in tests), so just throw the whole sections in nocov to be sure. maybe surface to Jim as well...

R/transpose.R Outdated
@@ -4,7 +4,7 @@ transpose = function(l, fill=NA, ignore.empty=FALSE, keep.names=NULL, make.names
if (is.character(make.names)) {
make.names=chmatch(make.names, names(l))
if (is.na(make.names))
stop("make.names='",make.names,"' not found in names of input")
stop("make.names not found in names of input")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make.names original value is overwritten already. Rather than complicate the logic (i.e. by one or two extra lines), just axed here, but easy to change.

test(1613.563, all(
all.equal(rbind(x,y), rbind(y,y), ignore.row.order=FALSE),
all.equal(rbind(x,y), rbind(y,y), ignore.row.order=TRUE),
all.equal(rbind(y,y), rbind(x,y), ignore.row.order=TRUE)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New test switches the order to hit the first-but-not-second-has-dups branch whose second-but-not-first counterpart is hit by the 2nd test already

@mattdowle mattdowle changed the title Closes #3758 and completes coverage of all files in R/ Completes coverage of all .R files Aug 12, 2019
@mattdowle mattdowle added this to the 1.12.4 milestone Aug 12, 2019
…between arguments so we can see where the real spaces inside quotes are. In this instance the diff now shows where the real space was added.
@mattdowle
Copy link
Member

Fantastic! I went through it and all looks good. Great comments. I added comment in the tests.Rraw for the new tests 2074.* file pointing back to this PR so we can get back to the comments if we ever need to.

@mattdowle mattdowle merged commit f7e82a5 into master Aug 12, 2019
@mattdowle mattdowle deleted the dt_covr branch August 12, 2019 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

by auto-naming is too greedy on eval-like columns
4 participants