gargoyle icon indicating copy to clipboard operation
gargoyle copied to clipboard

Warning: Error in watch: could not find function "watch"

Open Shelmith-Kariuki opened this issue 1 year ago • 8 comments

Hi @ColinFay ,

Thank you so much for {gargoyle}. A colleague of mine and I have been implementing it a lot.

Once in a while , I get this error when I launch the app for the first time. Do you know why? We've initiated, triggered and watched (through gargoyle::on()) our events correctly but still.

Screen Shot 2023-06-23 at 3 55 51 PM

Shelmith-Kariuki avatar Jun 23 '23 13:06 Shelmith-Kariuki

Hi, I also had the same problem. Restarting the session and/or emptying the environment did not solve the issue. What worked was to load {gargoyle} in R/run_app.R. Hope that helps @Shelmith-Kariuki Best,

cpauvert avatar Jul 09 '23 12:07 cpauvert

Hi @cpauvert and @Shelmith-Kariuki

Actually you are diagnosing the problem correctly, I think, in that the watch function cannot (always) be found.

For this neither emptying the environment nor restarting the session helps because your R session will still not know the function watch(). Solutions:

  1. If you call library(gargoyle) before, then you R session is aware of the watch function. However this is not recommended because there can be several possible watch functions, for example the package {testthat} also has a watch function; if you first do library(gargoyle) and then do library(testthat) and have an R script with watch() your code will use the watch from the last library(testthat)! Look at the following example
watch
#> Error in eval(expr, envir, enclos): object 'watch' not found
library(gargoyle)
watch
#> function(name, session = getDefaultReactiveDomain()) {
#>   session$userData[[name]]()
#> }
#> <bytecode: 0x55b4ec6c66b0>
#> <environment: namespace:gargoyle>
library(testthat)
#> 
#> Attaching package: 'testthat'
#> The following object is masked from 'package:gargoyle':
#> 
#>     watch
watch
#> function (path, callback, pattern = NULL, hash = TRUE) 
#> {
#>     prev <- dir_state(path, pattern, hash = hash)
#>     repeat {
#>         Sys.sleep(1)
#>         curr <- dir_state(path, pattern, hash = hash)
#>         changes <- compare_state(prev, curr)
#>         if (changes$n > 0) {
#>             keep_going <- TRUE
#>             try(keep_going <- callback(changes$added, changes$deleted, 
#>                 changes$modified))
#>             if (!isTRUE(keep_going)) 
#>                 return(invisible())
#>         }
#>         else {
#>         }
#>         prev <- curr
#>     }
#> }
#> <bytecode: 0x55b4ecb93fe0>
#> <environment: namespace:testthat>
  1. Therefor, one recommended way (see e.g. https://r-pkgs.org/dependencies-in-practice.html#sec-dependencies-in-imports-r-code), if you are working inside a package like {golem}, is to always prefix the function (which works also without library(gargoyle) and library(testthat) so try to write
watch
#> Error in eval(expr, envir, enclos): object 'watch' not found
gargoyle::watch
#> function(name, session = getDefaultReactiveDomain()) {
#>   session$userData[[name]]()
#> }
#> <bytecode: 0x5636015371a0>
#> <environment: namespace:gargoyle>
testthat::watch
#> function (path, callback, pattern = NULL, hash = TRUE) 
#> {
#>     prev <- dir_state(path, pattern, hash = hash)
#>     repeat {
#>         Sys.sleep(1)
#>         curr <- dir_state(path, pattern, hash = hash)
#>         changes <- compare_state(prev, curr)
#>         if (changes$n > 0) {
#>             keep_going <- TRUE
#>             try(keep_going <- callback(changes$added, changes$deleted, 
#>                 changes$modified))
#>             if (!isTRUE(keep_going)) 
#>                 return(invisible())
#>         }
#>         else {
#>         }
#>         prev <- curr
#>     }
#> }
#> <bytecode: 0x563601998670>
#> <environment: namespace:testthat>

instead of watch. This way you can also refer to testthat::watch(), and then to gargoyle::watch()or other watch()-functions without ambiguity, whenever you want.

ilyaZar avatar Jul 09 '23 16:07 ilyaZar

Thank you @ilyaZar for your extensive answer! I also directly thought of this, but the issue is that at this stage of the project I was not even calling gargoyle::watch() but only gargoyle::on(), similarly to @Shelmith-Kariuki apparently.

This is why I was surprised that the error message was

Warning: Error in watch: could not find function "watch"

but I could not traceback from where. Maybe gargoyle::on()`` uses watch()` somewhere without the canonical prefix?

If you have any lead, they would be most welcome!

cpauvert avatar Jul 09 '23 18:07 cpauvert

Actually not that I am aware of:

here is the code snippet related to the part which the function on() uses: https://github.com/ColinFay/gargoyle/blob/83234de417b9b0b39be9b8f1556e5df1968624b2/R/funs.R#L138-L148

The substitute call does generate an internal gargoyle::watch() for the observeEvent.

The full on() function is like so: https://github.com/ColinFay/gargoyle/blob/83234de417b9b0b39be9b8f1556e5df1968624b2/R/funs.R#L124-L149

It's a bit strange... By the way the full link to the file so you can check yourself https://github.com/ColinFay/gargoyle/blob/master/R/funs.R

Maybe you are changing the "session"? Currently the session parameter is not passed directly down from on to watch, see the issue #17 (solved by #18 ). This session-error went probably unnoticed for quite a while since one almost always is not changing the session.

You are having your App as a repo: could you start in a fresh R session? Maybe (probably you are already doing this but still):

call

golem::run_dev()

because it recompiles your package. Maybe some of the watch() instances you changed to gargoyle::watch() are not having the change yet in the compiled package version.

ilyaZar avatar Jul 09 '23 18:07 ilyaZar

Yep, was also looking! Thanks! BUT this dates https://github.com/ColinFay/gargoyle/commit/17423812fe166ab5e990ea0b432d76b17c8875b8 back to after the package was on the CRAN, and this is the version I installed. Trying out with the dev version now..

EDIT: yes this did the trick!

cpauvert avatar Jul 09 '23 18:07 cpauvert

ah that could be it :)

ilyaZar avatar Jul 09 '23 18:07 ilyaZar

Checking again that :

gargoyle::on

did correctly have the prefix! :+1: and if yes, I also then added {gargoyle} as a remote dependency to be sure in the future:

usethis::use_dev_package("gargoyle", remote = "ColinFay/gargoyle")

cpauvert avatar Jul 09 '23 19:07 cpauvert

I had this error with current versions. No watch statements so must be called internally (I had one on call which when removed also removed the error...)

Solved by adding @import gargoyle to the app_server.R script so gargoyle is always loaded and watch therefore found.

brucemoran avatar Jul 25 '24 15:07 brucemoran