klmr / box

Write reusable, composable and modular R code
https://klmr.me/box/
MIT License
862 stars 48 forks source link

Improve the debugging experience #288

Open johnhubertjj opened 2 years ago

johnhubertjj commented 2 years ago

Error description

May just be me missing something, but whenever I load an environment using the box architecture, and then call a function which contains a browser() within it, the debug mode loads up fine and works smoothly, but if I try to call View() on any object within the debug environment, I get the following error:

Error in View(df2) : could not find function "View"

does this mean I need to load the utils separately using box as well? It can be quite cumbersome to do so.

Example below:

If I have the file structure:

R/run.R R/fct_custom.R

run.R:

options(box.path = getwd())
box::use(R/fct_custom)

df <- mtcars

fct_custom$Manipulate_data(df=df)

R/fct_custom:

Manipulate_data <- function(df){
a <- 1 
browser()
View(df)
}

R version

platform       x86_64-apple-darwin15.6.0   
arch           x86_64                      
os             darwin15.6.0                
system         x86_64, darwin15.6.0        
status                                     
major          3                           
minor          6.3                         
year           2020                        
month          02                          
day            29                          
svn rev        77875                       
language       R                           
version.string R version 3.6.3 (2020-02-29)
nickname       Holding the Windsock

‘box’ version

‘1.1.2’

klmr commented 2 years ago

This is working as expected: the View function is not attached, because no package except ‘base’ is attached inside modules, see the related FAQ.

The solution is to import the relevant name, e.g.:

box::use(utils[View])
x1o commented 1 year ago

Neither this, nor box::use(r/core[...]) works for me on macOS Ventura 13.4, R 4.2, under RStudio:

Error in View(datasets::mtcars) : X11 is not available
klmr commented 1 year ago

The issue here is that RStudio overrides View so consequently you don’t want to actually use utils::View, you want to use the View that is attached to the global environment.

Unfortunately there is no really nice way to do this because of the somewhat hacky way RStudio injects itself into the R session, but the following works:

get('View', envir = .GlobalEnv)(datasets::mtcars)
x1o commented 1 year ago

Thank you!

nvelden commented 1 year ago

Would it be possible to make a specific browser() function for box modules or somehow import these basic utils functions automatically in browser mode? I keep forgetting to type get('View', envir = .GlobalEnv)(datasets::mtcars) or get('head', envir = .GlobalEnv)(mtcars) every time I am in debugging mode instead of just View(mtcars) or head(mtcars).

klmr commented 1 year ago

@nvelden I’m not happy with the current state of affairs myself. However, I don’t think providing a bunch of custom functions that replace the base R debugging utilities is the answer. In particular, it wouldn’t just be one function (browser()), it’s a whole bunch: debug(), debugonce(), trace(), setBreakpoint(), recover(), at the very least.

Rather, I think a better approach would be to hook into all these core R debugging utilities when ‘box’ is loaded. Then, when R drops into the debugger, ‘box’ could “attach” a utility environment that contains things like View() etc. However, this isn’t trivial (if it’s possible at all: browser() is an R primitive, so I can’t just inject my own R code into it. It might be enough to wrap browser(), but so far I haven’t gotten that to work.

D3SL commented 1 year ago

Sounds like the root issue here is that RStudio is starting to follow Microsoft's "embrace, extend, extinguish" pattern and is forcing non-standard behavior that breaks R itself.