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

Adds names(qenv/qenv.error) S3 methods #218

Open
wants to merge 37 commits into
base: main
Choose a base branch
from

Conversation

averissimo
Copy link
Contributor

@averissimo averissimo commented Oct 28, 2024

Pull Request

Changes description

  • qenv S4 class inherits from environment data class
  • Removes @env slot in favor of qenv
  • Replace all instances of @env with @.xData (slot created by parent class)

@averissimo averissimo marked this pull request as ready for review October 28, 2024 17:09
Copy link
Contributor

github-actions bot commented Oct 28, 2024

Unit Tests Summary

  1 files   10 suites   1s ⏱️
123 tests 121 ✅ 2 💤 0 ❌
220 runs  218 ✅ 2 💤 0 ❌

Results for commit faa843b.

♻️ This comment has been updated with latest results.

Copy link
Contributor

github-actions bot commented Oct 28, 2024

Unit Test Performance Difference

Test Suite $Status$ Time on main $±Time$ $±Tests$ $±Skipped$ $±Failures$ $±Errors$
qenv-class 👶 $+0.23$ $+5$ $0$ $0$ $0$
Additional test case details
Test Suite $Status$ Time on main $±Time$ Test Case
qenv-class 👶 $+0.05$ creates_a_locked_environment
qenv-class 👶 $+0.06$ creates_a_locked_environment_when_.xData_is_manually_defined
qenv-class 👶 $+0.01$ throws_error_when_.xData_is_not_an_environment
qenv-class 👶 $+0.10$ throws_error_when_id_and_code_length_doesn_t_match
qenv_constructor 👶 $+0.01$ does_not_allow_binding_to_be_added
qenv_constructor 👶 $+0.01$ does_not_allow_binding_to_be_modified
qenv_constructor 👶 $+0.02$ is_an_environment
qenv_constructor 👶 $+0.00$ ls_does_not_show_hidden_objects
qenv_constructor 👶 $+0.00$ ls_shows_available_objets
qenv_constructor 👶 $+0.00$ ls_shows_nothing_on_empty_environment
qenv_constructor 👶 $+0.00$ names_show_all_objects
qenv_constructor 💀 $0.01$ $-0.01$ parent_of_qenv_environment_is_locked
qenv_constructor 💀 $0.00$ $-0.00$ parent_of_qenv_environment_is_the_parent_of_.GlobalEnv
qenv_constructor 👶 $+0.01$ qenv_environment_is_locked
qenv_constructor 👶 $+0.00$ via_qenv_directly
qenv_constructor 👶 $+0.00$ via_slot
qenv_eval_code 👶 $+0.01$ .xData_in_qenv_is_always_a_sibling_of.GlobalEnv
qenv_eval_code 💀 $0.01$ $-0.01$ env_in_qenv_is_always_a_sibling_of.GlobalEnv
qenv_get_code 💀 $0.01$ $-0.01$ works_for_datanames_of_length_1
qenv_get_code 👶 $+0.01$ works_for_names_of_length_1
qenv_get_var 👶 $+0.01$ get_var_and_only_returns_objects_from_qenv_not_.GlobalEnv
qenv_within 👶 $+0.00$ multiline_expressions_are_evaluated
qenv_within 👶 $+0.01$ within.qenv_renturns_a_qenv_where_.xData_is_a_deep_copy_of_that_in_data_
qenv_within 💀 $0.01$ $-0.01$ within.qenv_renturns_a_qenv_where_env_is_a_deep_copy_of_that_in_data_

Results for commit dd2a739

♻️ This comment has been updated with latest results.

Copy link
Contributor

github-actions bot commented Oct 28, 2024

badge

Code Coverage Summary

Filename                         Stmts    Miss  Cover    Missing
-----------------------------  -------  ------  -------  ---------
R/qenv-class.R                       5       0  100.00%
R/qenv-concat.R                     10       0  100.00%
R/qenv-constructor.R                18      17  5.56%    76-119
R/qenv-errors.R                      4       4  0.00%    6-9
R/qenv-eval_code.R                  52       2  96.15%   99, 108
R/qenv-get_code.R                   28       0  100.00%
R/qenv-get_env.R                     3       1  66.67%   29
R/qenv-get_var.R                    27       0  100.00%
R/qenv-get_warnings.R               24       0  100.00%
R/qenv-join.R                       64       2  96.88%   211, 223
R/qenv-length.R                      2       0  100.00%
R/qenv-show.R                        1       1  0.00%    19
R/qenv-within.R                      8       0  100.00%
R/utils-get_code_dependency.R      191       1  99.48%   283
R/utils.R                           10       0  100.00%
TOTAL                              447      28  93.74%

Diff against main

Filename                Stmts    Miss  Cover
--------------------  -------  ------  --------
R/qenv-class.R             +5       0  +100.00%
R/qenv-constructor.R       +2      +4  -13.19%
R/qenv-errors.R            +4      +4  +100.00%
R/qenv-get_env.R            0      -2  +66.67%
R/qenv-get_var.R           +8       0  +100.00%
R/qenv-join.R             +18      +2  -3.12%
R/qenv-length.R            +2       0  +100.00%
TOTAL                     +39      +8  -1.36%

Results for commit: faa843b

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

@gogonzo gogonzo self-assigned this Oct 29, 2024
R/qenv-names.R Outdated
ls(get_env(x))
}

#' @rdname names.qenv
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to decide where to put names.qenv. At this moment within, eval_code, get_code are part of qenv documentation and they are described in the sections. Problem with some methods (names, within) is that they have generic in base and it is not obvious that one needs to call names.qenv.

Copy link
Contributor

@gogonzo gogonzo left a comment

Choose a reason for hiding this comment

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

Please test cover new functions

NAMESPACE Outdated
S3method("[[",qenv.error)
S3method("[[<-",qenv.error)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd like to preface that I'm more than happy to remove as this is **totally** nitpicking.

My reasoning adding this would be to make the API consistent

The 2 snippets below shows the **released/main** behavior and the assignments (<-) seem inconsistent with qenv.

It seems odd that with qenv.error the script runs a few more commands.

qenv object without errors

library(teal.code)
q <- qenv() |> within(a <- 2)
q$something <- 2
#> Error in `$<-`(`*tmp*`, something, value = 2): no method for assigning subsets of this S4 class
q[["another"]] <- 3
#> Error in `[[<-`(`*tmp*`, "another", value = 3): [[<- defined for objects of type "S4" only for subclasses of environment

q$something
#> Error in q$something: $ operator not defined for this S4 class
q[["another"]]
#> object 'another' not found
#> NULL

Created on 2024-10-29 with reprex v2.1.1

qenv object when there's an error in within code

library(teal.code)
q <- qenv() |> within(stop())
q$something <- 2
q[["another"]] <- 3

q$something
#> [1] 2
q[["another"]]
#> Error:  
#>  when evaluating qenv code:
#> stop()

Created on 2024-10-29 with reprex v2.1.1

Copy link
Contributor

Choose a reason for hiding this comment

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

We don't need to fence all possible methods. There is large set of the methods inherited from environment, it is important that officially supported functions are mentioned in the docs of qenv. We need to mention inherited working methods but not add them. What I would add though to qenv.error is $.qenv.error, [[.qenv.error, as.list.qenv.error, ls.qenv.error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ls.qenv.error cannot be added, but it will still give an error, so no harm there

Copy link
Contributor

Choose a reason for hiding this comment

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

hmm, there is a difference between throwing error and returning error. ls(<qenv.error>) will throw while names.qenv.error(<qenv.error>) will return error. The first one needs to be tryCatched while second one not. We need to check if ls(data()) in teal internals doesn't throw because of this (probably not as teal is protected against any types of errors)

Copy link
Contributor Author

@averissimo averissimo left a comment

Choose a reason for hiding this comment

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

Some topics to discuss on this implementation

@@ -31,7 +31,7 @@ setMethod("eval_code", signature = c("qenv", "character"), function(object, code
id <- sample.int(.Machine$integer.max, size = 1)

object@id <- c(object@id, id)
object@env <- rlang::env_clone(object@env, parent = parent.env(.GlobalEnv))
object@.xData <- rlang::env_clone(object@.xData, parent = parent.env(.GlobalEnv))
Copy link
Contributor Author

@averissimo averissimo Oct 29, 2024

Choose a reason for hiding this comment

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

{rlang} functions don't play nicely with this approach, so we need to access the slot directly

🔴 Could this lack of support from {rlang} be a blocker for this new approach?

pkgload::load_all("teal.code")
#> ℹ Loading teal.code

q1 <- qenv()
rlang::is_environment(q1)
#> [1] FALSE
base::is.environment(q1)
#> [1] TRUE

rlang::env_clone(q1)
#> Error in `rlang::env_clone()`:
#> ! `env` must be an environment, not a <qenv> object.

rlang::is_environment
#> function(x) {
#>   typeof(x) == "environment"
#> }
#> <bytecode: 0x65127a0d6b08>
#> <environment: namespace:rlang>
typeof(q1)
#> [1] "S4"

Created on 2024-10-29 with reprex v2.1.1

@@ -55,3 +55,29 @@ setMethod("[[", signature = c("qenv", "ANY"), function(x, i) {
class = c("validation", "try-error", "simpleError")
))
}

#' @export
`$.qenv.error` <- function(x, name) {
Copy link
Contributor Author

@averissimo averissimo Oct 29, 2024

Choose a reason for hiding this comment

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

🔴 Should we add this method and have it behave just like [[?

We need to allow $ to retrieve existing properties of qenv.error, as conditionMessage(x) will try to access x$message, x$call and x$trace.

return(NextMethod("$", x))
}

class(x) <- setdiff(class(x), "qenv.error")
Copy link
Contributor Author

@averissimo averissimo Oct 29, 2024

Choose a reason for hiding this comment

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

ℹ️ Safeguard to prevent infinite recursion, this can be "safely" removed if reviewer deems necessary

@@ -1,19 +1,67 @@
testthat::describe("qenv inherits from environment: ", {
Copy link
Contributor Author

@averissimo averissimo Oct 29, 2024

Choose a reason for hiding this comment

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

Please test cover new functions

ℹ️ Added tests that addressed last comment before the "change" (covering a wider range of functionalities)

Copy link
Contributor

@gogonzo gogonzo left a comment

Choose a reason for hiding this comment

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

There are some @env remaining in R/ directory . Also there shouldn't be any mention about internal slots (regex:#'.+@(env|.xData|code|id|warnings|messages) in the documentation @ - please replace them with something implicit.
(you can leave join docs unchanged - this is a bigger problem)

@@ -23,9 +45,7 @@
#'
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd add usage of names, [[ and $ to the examples section somewhere before # retrieve code. This could be a "section" # extracting objects from qenv

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See 0a644988135a098665-af7054b837b.

I may have gone a bit overboard by including these methods in the usage section, WDYT?

tests/testthat/test-qenv_within.R Outdated Show resolved Hide resolved
R/qenv-constructor.R Outdated Show resolved Hide resolved
R/qenv-constructor.R Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants