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

[DO NOT MERGE] Re-worked tooling for Python environments in REMIND #19

Draft
wants to merge 47 commits into
base: main
Choose a base branch
from

Conversation

tonnrueter
Copy link

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 environment
  • checkPythonEnv.R: Determines the location of interpreter binary in REMINDs Python environment. Works with system Python as well as with venv/conda based virtual Python environments
  • checkPythonRequirements.R: Checks if external Python dependencies are present in the Python environment
  • checkPythonDeps.R: Check if external Python dependencies can actually be imported. Intended to be used before starting a REMIND run

REMOVED

  • pythonBinPath.R: This replaced by checkPythonEnv.R
  • writePythonVirtualEnvLockFile.R/createResultsfolderPythonVirtualEnv.R: This was absorbed into archivePythonEnv.R
  • updatePythonVirtualEnv.R: Do not allow manipulation of the REMIND Python environment from REMIND

@tonnrueter tonnrueter changed the title [DO NOT MERGE] Re-work of utilities for handling Python environments in REMIND [DO NOT MERGE] Re-worked tooling for Python environments in REMIND Aug 7, 2024
@pascal-sauer pascal-sauer marked this pull request as draft August 8, 2024 06:50
@pascal-sauer
Copy link
Contributor

You can mark a PR as draft (which I just did) so it cannot be merged :)

Copy link
Contributor

@pascal-sauer pascal-sauer left a 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/archivePythonEnv.R Outdated Show resolved Hide resolved
R/archivePythonEnv.R Outdated Show resolved Hide resolved
R/archivePythonEnv.R Outdated Show resolved Hide resolved
R/archivePythonEnv.R Outdated Show resolved Hide resolved
R/archivePythonEnv.R Outdated Show resolved Hide resolved
nomatch <- rep(TRUE, length(requiredPackages))
}
# Error handling when dependencies are missing or versions mismatch
switch(action,
Copy link
Contributor

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?

Copy link
Author

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

Copy link
Contributor

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") {
Copy link
Contributor

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.

Copy link
Author

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 Show resolved Hide resolved
},
error = function(e) {
# Need to use <<- here to assign to the variable in the parent environment
missingDependencies <<- c(missingDependencies, paste0(dependencyString, " (missing) ")) # nolint
Copy link
Contributor

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?

Copy link
Author

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

Copy link
Contributor

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 😉

Copy link
Author

@tonnrueter tonnrueter Aug 26, 2024

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,
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants