Debugging
Misc
Rubber Duck Method
- Beg, borrow, steal, buy, fabricate or otherwise obtain a rubber duck (bathtub variety).
- Note: In a pinch a coworker might be able to substitute for the duck, however, it is often preferred to confide mistakes to the duck instead of your coworker.
- Place rubber duck on desk and inform it you are just going to go over some code with it, if that’s all right.
- Explain to the duck what your code is supposed to do, and then go into detail and explain your code line by line.
- At some point you will tell the duck what you are doing next and then realise that that is not in fact what you are actually doing. The duck will sit there serenely, happy in the knowledge that it has helped you on your way.
- Beg, borrow, steal, buy, fabricate or otherwise obtain a rubber duck (bathtub variety).
Silver Searcher - Fast code searching tool
- Basic usage for debugging:
ag "my error message" - Example (source)
heroku runexecutes a script and the error message has the words “could not be mailed.”- From your local project directory,
agtakes that message string as input and outputs the paths to the files with that string and the line of code with line number.
- Basic usage for debugging:
set_function_params: Helper function that assigns all argument values of a function to the global environment (source)Code
#' Set function parameters to an environment. #' #' This function is designed to help debug functions. It will attempt to set all #' the default parameter values to the specified environment (global environment #' by default). This is useful for when you want to execute code within the #' function definition interactively but need the parameters set in the current #' environment. #' #' **Warning:** This function will modify the global environment and therefore #' violates CRAN policy #' ["Packages should not modify the global environment (user’s workspace)"] #' (https://cran.r-project.org/web/packages/policies.html#Source-packages). #' #' @param FUN the function to assign parameters to an environment. #' @param envir the environment to assign the variables to. Defaults to the #' global environment. #' @param verbose whether to return the data frame invisibly or to print the results. #' @return a data frame where row names correspond to the parameter name with #' two columns: `set` which is logical indicating if the variable was set #' and `value` with a character representation of the variable value. set_function_params <- function(FUN, envir = globalenv(), verbose = interactive()) { params <- formals(FUN) params_set <- data.frame(row.names = names(params), set = rep(FALSE, length(params)), value = rep(NA_character_, length(params))) for(param in names(params)) { value <- params[[param]] if(!missing(value)) { if(is.character(value)) { assign(param, value, envir = envir) params_set[param,]$value <- value } else { assign(param, eval(value), envir = envir) params_set[param,]$value <- eval(value) } params_set[param,]$set <- TRUE } } if(verbose) { return(params_set) } else { invisible(params_set) } }
R
TipPackages
- {foodwebr} - Visualize function dependencies
- {flow} - Tools to visualize as flow diagrams the logic of functions, expressions or scripts and ease debugging
- {icecream} - Makes print debugging easier. It allows you to print out an expression, its value and (optionally) which function and file the call originated in.
- {tableboom} - Inspect Intermediate Steps of All Calls in R Script Using ‘boomer’ and Turn the Output Into HTML Table
Show call stack for warnings (source)
f1 = function() warning("boo") f2 = function() f1() f3 = function() f2() f3() #> Warning in f1() : boo options(showWarnCalls=TRUE) f3() #> Warning in f1() : boo #> Calls: f3 -> f2 -> f1
Python
TipPackages
- {{refcycle}} - Provides support for creating, analyzing, and visualizing graphs of Python objects and the references between them. It’s intended to aid in debugging reference-related problems, for example:
- Figuring out why an object is still alive after it should have been deleted.
- Detecting reference cycles that may be preventing objects from being collected by the regular reference-count-based garbage collection.
- Finding out why garbage collection is putting objects into
gc.garbage.
- {{code2flow}} - Function dependency flow charts
breakpoint(Docs)- Place function on the line above the line that you think is causing the error
- Once you’re in the python debugger (PDB), you can run any python code you want, just as if you were in a REPL. So once you finde the exact place that has caused the error, you try different solutions (e.g. setting variables to different values, importing functions, etc.) in order to see if it works.
- Example (source)
- Add
breakpointto script
- Error from the
exceptline was tripped, so the problem must be in thetrychunk - The problem isn’t
printorsleep, sobreakpointis placed above thesend_message_as_pybitesfunction
- Error from the
- Rerun script that gave the error
- The line below the
breakpointfunction is returned and PDP (Python DeBugger) is opened lorlistcommand returns 11 lines around the returned line which issend_message_as_pybites(the arrow marks where the returned line is)
- The line below the
- Step into the function
- Since the line below the
breakpointis a function, you can usedsorstepto “step” into that function and look at its code. - The output shows us it is now in the
utils.pyfile - Now, using the command
lagain shows 11 lines around the function definition line
- Since the line below the
- Use
nextto execute the next line of code
nornextexecutes the next line of code. It can also be used on function calls. Whilestepgoes to the function,nextjust executes the line.- If you type an of the variables (e.g. sender, receiver, etc.), it’ll show you the current value
- Using
lagain shows 11 lines around the current line and allows you to see where you are in the scipt.
- Continue with
nextuntil the error is triggered
nextexecutes theThreadfunction to create a thread object which is fine, but whenthread.saveis executed in the next step, the error is triggered.
- Add
