-
Notifications
You must be signed in to change notification settings - Fork 5
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
[DO NOT MERGE] Re-worked tooling for Python environments in REMIND #19
base: main
Are you sure you want to change the base?
Conversation
You can mark a PR as draft (which I just did) so it cannot be merged :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Impressive work! Some of the problems you solve here I suspect have already been solved in other places (R's numeric_version, python modules) that we should maybe use instead as they have been more thoroughly tested by the community.
R/checkPythonDeps.R
Outdated
nomatch <- rep(TRUE, length(requiredPackages)) | ||
} | ||
# Error handling when dependencies are missing or versions mismatch | ||
switch(action, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a lot of code duplication. What about something like this:
f <- switch(action,
stop = stop,
warn = warning,
note = message,
pass = function(...) TRUE
)
And then you only need the block once and instead of e.g. stop
you call f
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea, however if the stop/warn messaging is moved to a dedicated function (let's call it notifyUser
), the origin of the error is obfuscated, e.g.:
anotherFunction <- function() {
[..do things, error occurs..]
notifyUser("stop", "foobar")
}
yields Error in notifyUser("stop", "error message") : error message
instead of Error in anotherFunction [...]
.
I consolidated the error message creation now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What a shame, and it seems stop does not have a way to include the previous call on the call stack in the error message instead :/
#' @param depString Dependency string such as "numpy<=2.0" | ||
#' @param style Style of the dependency string. Either "pip" or "conda" | ||
#' @return A named list representation of the Pzthon package name and version | ||
extractPythonDependency <- function(depString, style = "pip") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This again feels like it should already exist in a python module. Writing this kind of code from scratch seems very risky to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, Python can do this, however we need R to do it, too 😬 This function is called before we can rely on using Python in REMIND
R/checkPythonDeps.R
Outdated
}, | ||
error = function(e) { | ||
# Need to use <<- here to assign to the variable in the parent environment | ||
missingDependencies <<- c(missingDependencies, paste0(dependencyString, " (missing) ")) # nolint |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<<-
should really be avoided if at all possible. Is it possible to return what you want to add here and then add it in a scope where missingDependencies is accessible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was not able to find another way to access missingDependencies
form the error callback. I'd argue that this is the exception to the (otherwise perfectly fine) rule to avoid <<-
, as the error case is two-fold: We're not only interested in dependencies that cannot be imported (which would trigger the error callback) but also a version mismatch (strict mode), where the dependency can be imported but has a version different from what's listed in the requirements.
I wanna respect your best R-practices here: If you strictly oppose <<-
-usage, I'll isolate the whole try-catch-block in a separate function that returns NULL if everything's fine, else returns a string giving a reason
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do strictly oppose <<-
, but I want to stress this is not "my" best R-practice 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imma make it a function then :)
I learned a lot about implicit return values of the tryCatch
-statement in R and found a way to remove <<-
👍
} | ||
# Error handling when dependencies are missing | ||
if (length(missingDependencies) > 0) { | ||
switch(action, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my suggestion further below
Please do not merge this PR since it breaks API I still need some time to make some changes to REMIND that use these new functions
NEW
archivePythonEnv.R
: Create a file listing all Python packages installed in the provided Python environmentcheckPythonEnv.R
: Determines the location of interpreter binary in REMINDs Python environment. Works with system Python as well as withvenv
/conda
based virtual Python environmentscheckPythonRequirements.R
: Checks if external Python dependencies are present in the Python environmentcheckPythonDeps.R
: Check if external Python dependencies can actually be imported. Intended to be used before starting a REMIND runREMOVED
pythonBinPath.R
: This replaced bycheckPythonEnv.R
writePythonVirtualEnvLockFile.R
/createResultsfolderPythonVirtualEnv.R
: This was absorbed intoarchivePythonEnv.R
updatePythonVirtualEnv.R
: Do not allow manipulation of the REMIND Python environment from REMIND