From 94ca7ffdf47d66b33ad6b867d8581362431c6b9b Mon Sep 17 00:00:00 2001 From: Dawid Kaledkowski Date: Tue, 27 May 2025 11:34:51 +0200 Subject: [PATCH 01/11] WIP --- R/teal_data-class.R | 23 ++++++++--------------- R/teal_data-constructor.R | 3 +-- man/teal_data-class.Rd | 15 --------------- man/teal_data.Rd | 2 +- 4 files changed, 10 insertions(+), 33 deletions(-) diff --git a/R/teal_data-class.R b/R/teal_data-class.R index 46baa004b..db74165e2 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -35,11 +35,7 @@ setOldClass("join_keys") setClass( Class = "teal_data", contains = "qenv", - slots = c(join_keys = "join_keys", verified = "logical"), - prototype = list( - join_keys = join_keys(), - verified = logical(0) - ) + slots = c(join_keys = "join_keys", verified = "logical") ) #' It initializes the `teal_data` class @@ -50,13 +46,13 @@ setClass( setMethod( "initialize", "teal_data", - function(.Object, .xData = list(), join_keys = join_keys(), code = list(), ...) { # nolint: object_name. - # Allow .xData to be a list and convert it to an environment - if (!missing(.xData) && inherits(.xData, "list")) { - .xData <- rlang::env_clone(list2env(.xData), parent = parent.env(.GlobalEnv)) # nolint: object_name. - lockEnvironment(.xData, bindings = TRUE) - } + function(.Object, .xData, join_keys, code, ...) { # nolint: object_name. + print("init teal_data") + if (missing(.xData)) .xData <- new.env() + if (missing(join_keys)) join_keys <- teal.data::join_keys() + if (missing(code)) code <- character(0L) args <- list(...) + checkmate::assert_environment(.xData) checkmate::assert_class(join_keys, "join_keys") checkmate::assert_list(args, names = "named") @@ -67,15 +63,12 @@ setMethod( if (is.language(code)) { code <- paste(lang2calls(code), collapse = "\n") } - if (length(code)) { - code <- paste(code, collapse = "\n") - } methods::callNextMethod( .Object, .xData, join_keys = join_keys, - verified = (length(args$code) == 0L && length(.xData) == 0L), + verified = (length(code) == 0L && length(.xData) == 0L), code = code2list(code), ... ) diff --git a/R/teal_data-constructor.R b/R/teal_data-constructor.R index 25a705342..2c308f723 100644 --- a/R/teal_data-constructor.R +++ b/R/teal_data-constructor.R @@ -48,13 +48,12 @@ teal_data <- function(..., if (inherits(join_keys, "join_key_set")) { join_keys <- teal.data::join_keys(join_keys) } - if (length(data_objects) > 0 && !checkmate::test_names(names(data_objects), type = "named")) { stop("Dot (`...`) arguments on `teal_data()` must be named.") } methods::new( "teal_data", - .xData = data_objects, + .xData = list2env(data_objects), code = code, join_keys = join_keys ) diff --git a/man/teal_data-class.Rd b/man/teal_data-class.Rd index d046b4bd3..a232a40ca 100644 --- a/man/teal_data-class.Rd +++ b/man/teal_data-class.Rd @@ -36,19 +36,4 @@ proven to yield contents of \verb{@.xData}. Used internally. See \code{\link[=verify]{verify()}} for more details.} }} -\section{Code}{ - - - -Each code element is a character representing one call. Each element is named with the random -identifier to make sure uniqueness when joining. Each element has possible attributes: -\itemize{ -\item \code{warnings} (\code{character}) the warnings output when evaluating the code element. -\item \code{messages} (\code{character}) the messages output when evaluating the code element. -\item \code{dependency} (\code{character}) names of objects that appear in this call and gets affected by this call, -separated by \verb{<-} (objects on LHS of \verb{<-} are affected by this line, and objects on RHS are affecting this line). -} - -} - \keyword{internal} diff --git a/man/teal_data.Rd b/man/teal_data.Rd index a53804d60..e7cf04588 100644 --- a/man/teal_data.Rd +++ b/man/teal_data.Rd @@ -41,7 +41,7 @@ A \code{teal_data} is meant to be used for reproducibility purposes. The class i \item It inherits from the environment and methods such as \code{\link{$}}, \code{\link[=get]{get()}}, \code{\link[=ls]{ls()}}, \code{\link[=as.list]{as.list()}}, \code{\link[=parent.env]{parent.env()}} work out of the box. \item \code{teal_data} is a locked environment, and data modification is only possible through the -\code{\link[teal.code:eval_code]{teal.code::eval_code()}} and \code{\link[teal.code:eval_code]{within.qenv()}} functions. +\code{\link[teal.code:eval_code]{teal.code::eval_code()}} and \code{\link[teal.code:within.qenv]{within.qenv()}} functions. \item It stores metadata about the code used to create the data (see \code{\link[=get_code,teal_data-method]{get_code()}}). \item It supports slicing (see \code{\link[teal.code:subset-qenv]{teal.code::subset-qenv}}) \item Is immutable which means that each code evaluation does not modify the original \code{teal_data} From 246bd309154d1d892711238c5ab95aef167df8d5 Mon Sep 17 00:00:00 2001 From: Dawid Kaledkowski Date: Tue, 27 May 2025 12:05:54 +0200 Subject: [PATCH 02/11] roxy --- man/teal_data-class.Rd | 15 +++++++++++++++ man/teal_data.Rd | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/man/teal_data-class.Rd b/man/teal_data-class.Rd index a232a40ca..d046b4bd3 100644 --- a/man/teal_data-class.Rd +++ b/man/teal_data-class.Rd @@ -36,4 +36,19 @@ proven to yield contents of \verb{@.xData}. Used internally. See \code{\link[=verify]{verify()}} for more details.} }} +\section{Code}{ + + + +Each code element is a character representing one call. Each element is named with the random +identifier to make sure uniqueness when joining. Each element has possible attributes: +\itemize{ +\item \code{warnings} (\code{character}) the warnings output when evaluating the code element. +\item \code{messages} (\code{character}) the messages output when evaluating the code element. +\item \code{dependency} (\code{character}) names of objects that appear in this call and gets affected by this call, +separated by \verb{<-} (objects on LHS of \verb{<-} are affected by this line, and objects on RHS are affecting this line). +} + +} + \keyword{internal} diff --git a/man/teal_data.Rd b/man/teal_data.Rd index e7cf04588..a53804d60 100644 --- a/man/teal_data.Rd +++ b/man/teal_data.Rd @@ -41,7 +41,7 @@ A \code{teal_data} is meant to be used for reproducibility purposes. The class i \item It inherits from the environment and methods such as \code{\link{$}}, \code{\link[=get]{get()}}, \code{\link[=ls]{ls()}}, \code{\link[=as.list]{as.list()}}, \code{\link[=parent.env]{parent.env()}} work out of the box. \item \code{teal_data} is a locked environment, and data modification is only possible through the -\code{\link[teal.code:eval_code]{teal.code::eval_code()}} and \code{\link[teal.code:within.qenv]{within.qenv()}} functions. +\code{\link[teal.code:eval_code]{teal.code::eval_code()}} and \code{\link[teal.code:eval_code]{within.qenv()}} functions. \item It stores metadata about the code used to create the data (see \code{\link[=get_code,teal_data-method]{get_code()}}). \item It supports slicing (see \code{\link[teal.code:subset-qenv]{teal.code::subset-qenv}}) \item Is immutable which means that each code evaluation does not modify the original \code{teal_data} From 427586b9224edf8f69d3b0b228a325163218e938 Mon Sep 17 00:00:00 2001 From: Dawid Kaledkowski Date: Tue, 27 May 2025 13:01:36 +0200 Subject: [PATCH 03/11] fix split_code error --- R/teal_data-class.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/teal_data-class.R b/R/teal_data-class.R index db74165e2..56d3538b7 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -90,6 +90,7 @@ code2list <- function(code) { if (length(code) == 0) { return(list()) } + code <- paste(code, collapse = "\n") parsed_code <- parse(text = code, keep.source = TRUE) From bdcba9c4b0de0c0c40d8ecb838a9034f7994a036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Thu, 29 May 2025 14:48:51 +0100 Subject: [PATCH 04/11] cleanup: remove print debug --- R/teal_data-class.R | 1 - 1 file changed, 1 deletion(-) diff --git a/R/teal_data-class.R b/R/teal_data-class.R index 56d3538b7..0b9d6918d 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -47,7 +47,6 @@ setMethod( "initialize", "teal_data", function(.Object, .xData, join_keys, code, ...) { # nolint: object_name. - print("init teal_data") if (missing(.xData)) .xData <- new.env() if (missing(join_keys)) join_keys <- teal.data::join_keys() if (missing(code)) code <- character(0L) From 98bd4cafcfdc2337571c2959c948ed1c38fa0c65 Mon Sep 17 00:00:00 2001 From: Marcin <133694481+m7pr@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:51:34 +0200 Subject: [PATCH 05/11] change message in show method for `teal_data` (#372) I've suggested "code verified/unverified" because: 1. It's concise and clear 2. It focuses on what's actually being verified (the code that created the data) 3. It removes the redundant "teal_data object" since this is already known from the context --- R/teal_data-show.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/teal_data-show.R b/R/teal_data-show.R index 4ce54d8b8..96f10acc2 100644 --- a/R/teal_data-show.R +++ b/R/teal_data-show.R @@ -12,9 +12,9 @@ #' @export setMethod("show", signature = "teal_data", function(object) { if (object@verified) { - cat("\u2705\ufe0e", "verified teal_data object\n") + cat("\u2705\ufe0e", "code verified\n") } else { - cat("\u2716", "unverified teal_data object\n") + cat("\u2716", "code unverified\n") } methods::callNextMethod(object) invisible(object) From 152a7ff05c44ec046fa0055963d88fd70111fc7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Fri, 6 Jun 2025 12:21:50 +0100 Subject: [PATCH 06/11] chore: bump version --- DESCRIPTION | 2 +- R/teal_data-class.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index d3e76b0b6..71472739a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -29,7 +29,7 @@ URL: https://insightsengineering.github.io/teal.data/, BugReports: https://github.com/insightsengineering/teal.data/issues Depends: R (>= 4.0), - teal.code (>= 0.6.0) + teal.code (>= 0.6.1.9002), Imports: checkmate (>= 2.1.0), lifecycle (>= 0.2.0), diff --git a/R/teal_data-class.R b/R/teal_data-class.R index 0b9d6918d..558b26ab1 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -26,7 +26,7 @@ setOldClass("join_keys") #' Access or modify with [join_keys()]. #' @slot verified (`logical(1)`) flag signifying that code in `@code` has been #' proven to yield contents of `@.xData`. -#' Used internally. See [`verify()`] for more details. +#' Used internally. See [`teal.data::verify()`] for more details. #' #' @inheritSection teal.code::`qenv-class` Code #' From fd4a6b3a94ae25bc32a74c136c4d79154a3cd079 Mon Sep 17 00:00:00 2001 From: Dawid Kaledkowski Date: Mon, 9 Jun 2025 08:04:52 +0200 Subject: [PATCH 07/11] add a Remotes to teal.code --- DESCRIPTION | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DESCRIPTION b/DESCRIPTION index 414c8de71..42bb8dcd0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -45,6 +45,8 @@ Suggests: VignetteBuilder: knitr, rmarkdown +Remotes: + insightsengineering/teal.code@teal_reportable RdMacros: lifecycle Config/Needs/verdepcheck: insightsengineering/teal.code, mllg/checkmate, From 8585f6c7929d63f37e63bcfddd4cc01548e26cfa Mon Sep 17 00:00:00 2001 From: Dawid Kaledkowski Date: Mon, 9 Jun 2025 08:18:18 +0200 Subject: [PATCH 08/11] fix lintr, remove cyclocomp_linter warning which is not in defaults --- .lintr | 3 +-- R/join_keys-utils.R | 3 +-- R/teal_data-class.R | 2 +- R/topological_sort.R | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.lintr b/.lintr index 62b3fc4f4..3377b6466 100644 --- a/.lintr +++ b/.lintr @@ -1,5 +1,4 @@ linters: linters_with_defaults( line_length_linter = line_length_linter(120), - object_usage_linter = NULL, - cyclocomp_linter = NULL + object_usage_linter = NULL ) diff --git a/R/join_keys-utils.R b/R/join_keys-utils.R index 7ace0e74f..da084e972 100644 --- a/R/join_keys-utils.R +++ b/R/join_keys-utils.R @@ -39,8 +39,7 @@ assert_compatible_keys <- function(join_key_1, join_key_2) { } } - # otherwise they are compatible - return(TRUE) + TRUE # otherwise they are compatible } #' Validate parent-child key diff --git a/R/teal_data-class.R b/R/teal_data-class.R index 558b26ab1..d571dc321 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -47,7 +47,7 @@ setMethod( "initialize", "teal_data", function(.Object, .xData, join_keys, code, ...) { # nolint: object_name. - if (missing(.xData)) .xData <- new.env() + if (missing(.xData)) .xData <- new.env() # nolint: object_name. if (missing(join_keys)) join_keys <- teal.data::join_keys() if (missing(code)) code <- character(0L) args <- list(...) diff --git a/R/topological_sort.R b/R/topological_sort.R index 413878373..7d7f65e54 100644 --- a/R/topological_sort.R +++ b/R/topological_sort.R @@ -50,7 +50,7 @@ topological_sort <- function(graph) { paste0(setdiff(names(in_degrees), sorted), collapse = " ") ) } else { - return(sorted) + sorted } } From db7ff22b95d3c8090d5ba12e3fc26518b682cd47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Thu, 12 Jun 2025 10:28:55 +0100 Subject: [PATCH 09/11] chore: revert to @main before merge --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 42bb8dcd0..64e17184c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -46,7 +46,7 @@ VignetteBuilder: knitr, rmarkdown Remotes: - insightsengineering/teal.code@teal_reportable + insightsengineering/teal.code@main RdMacros: lifecycle Config/Needs/verdepcheck: insightsengineering/teal.code, mllg/checkmate, From 07d1694a55a8c5abbd7aeaf528e8cc6197cb8ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Thu, 12 Jun 2025 15:43:20 +0100 Subject: [PATCH 10/11] docs: update NEWS --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 63d1ec75e..5ca356932 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # teal.data 0.7.0.9003 +### Breaking changes + +* Print of a `teal_data` object now shows "code (un)verified" instead of "(un)verified teal_data object". + # teal.data 0.7.0 ### Breaking changes From 02eba6831763716b02ffe89376eb0672993bb6f0 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 12 Jun 2025 14:46:19 +0000 Subject: [PATCH 11/11] [skip roxygen] [skip vbump] Roxygen Man Pages Auto Update --- man/teal_data.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/teal_data.Rd b/man/teal_data.Rd index a53804d60..e7cf04588 100644 --- a/man/teal_data.Rd +++ b/man/teal_data.Rd @@ -41,7 +41,7 @@ A \code{teal_data} is meant to be used for reproducibility purposes. The class i \item It inherits from the environment and methods such as \code{\link{$}}, \code{\link[=get]{get()}}, \code{\link[=ls]{ls()}}, \code{\link[=as.list]{as.list()}}, \code{\link[=parent.env]{parent.env()}} work out of the box. \item \code{teal_data} is a locked environment, and data modification is only possible through the -\code{\link[teal.code:eval_code]{teal.code::eval_code()}} and \code{\link[teal.code:eval_code]{within.qenv()}} functions. +\code{\link[teal.code:eval_code]{teal.code::eval_code()}} and \code{\link[teal.code:within.qenv]{within.qenv()}} functions. \item It stores metadata about the code used to create the data (see \code{\link[=get_code,teal_data-method]{get_code()}}). \item It supports slicing (see \code{\link[teal.code:subset-qenv]{teal.code::subset-qenv}}) \item Is immutable which means that each code evaluation does not modify the original \code{teal_data}