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

enhance CMakeMake easyblock to check whether correct Python installation was picked up by cmake #3233

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from

Conversation

MartinsNadia
Copy link

Sanity check to verify if Cmake apply the new policy CMP0094

ebrootpython_path = os.getenv('EBROOTPYTHON')
if all(path and ebrootpython_path in path for path in [pythonExecPath, pythonIncludePath, pythonLibraryPath]):
self.log.info("Python related paths configured correctly.")
return out
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the return statement out of the if/else block, it is hidden here.

self.log.info("Python include path: %s", pythonIncludePath)
self.log.info("Python library path: %s", pythonLibraryPath)
# Check if paths include EBROOTPYTHON
ebrootpython_path = os.getenv('EBROOTPYTHON')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes that EBROOTPYTHON is set, what happens if it isn't?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine that what you want to do is complain if pythonExecPath (and friends) are set but no Python dependency is found

Comment on lines 334 to 336
self.log.info("Python executable path: %s", pythonExecPath)
self.log.info("Python include path: %s", pythonIncludePath)
self.log.info("Python library path: %s", pythonLibraryPath)
Copy link
Member

@ocaisa ocaisa Feb 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would only print these if they have a value (so move them up into your if/elif loop)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not only that: You could have them multiple times when you consider Python_EXECUTABLE and Python3_EXECUTABLE or the variables may be completely unset if the CMake file didn't use Python at all

Maybe create thos variables as empty lists?


# Search for Python paths in each line
for line in lines:
if line.startswith('Python3_EXECUTABLE:FILEPATH='):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like these are only guaranteed for CMake 3.16+ so should probably make this check conditional on that version

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes maybe use a regex? Python[2-3]?_EXECUTABLE?

self.log.info("Python include path: %s", pythonIncludePath)
self.log.info("Python library path: %s", pythonLibraryPath)
# Check if paths include EBROOTPYTHON
ebrootpython_path = os.getenv('EBROOTPYTHON')
Copy link
Member

@ocaisa ocaisa Feb 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ebrootpython_path = os.getenv('EBROOTPYTHON')
ebrootpython_path = get_software_root("Python")
if pythonExecPath and not ebrootpython_path:
raise EasyBuildError("Python related path (%s) found but no Python dependency included, check log" % pythonExecPath)

# Search for Python paths in each line
for line in lines:
if line.startswith('Python3_EXECUTABLE:FILEPATH='):
pythonExecPath = line.split('=')[1].strip()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nitpicking suggestion: let's not start using CamelCase for variable names (we only use that for class names), so please use python_exec_path, python_include_path, python_library_path

@boegel boegel changed the title Sanity Check for Python Configuration enhance CMakeMake easyblock to check whether correct Python installation was picked up by cmake Feb 28, 2024
Copy link
Contributor

@Flamefire Flamefire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a bit more tricky than it seems...


# sanitycheck for the configuration step
self.log.info("Checking python paths")
with open('CMakeCache.txt', 'r') as file:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should handle the case that this file may not exist. E.g. when configure_cmd != DEFAULT_CONFIGURE_CMD anything can happen.

# sanitycheck for the configuration step
self.log.info("Checking python paths")
with open('CMakeCache.txt', 'r') as file:
lines = file.readlines()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use readfile(...).split('\n')?


# Search for Python paths in each line
for line in lines:
if line.startswith('Python3_EXECUTABLE:FILEPATH='):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes maybe use a regex? Python[2-3]?_EXECUTABLE?

Comment on lines 334 to 336
self.log.info("Python executable path: %s", pythonExecPath)
self.log.info("Python include path: %s", pythonIncludePath)
self.log.info("Python library path: %s", pythonLibraryPath)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not only that: You could have them multiple times when you consider Python_EXECUTABLE and Python3_EXECUTABLE or the variables may be completely unset if the CMake file didn't use Python at all

Maybe create thos variables as empty lists?

self.log.info("Python library path: %s", pythonLibraryPath)
# Check if paths include EBROOTPYTHON
ebrootpython_path = os.getenv('EBROOTPYTHON')
if all(path and ebrootpython_path in path for path in [pythonExecPath, pythonIncludePath, pythonLibraryPath]):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above: pythonExecPath & co might not have been set at all. And maybe path.startswith(ebrootpython_path)? We possibly need to take symlinks into account too: either of the 2 might be a resolved symlink or not.

except FileNotFoundError:
self.log.warning("CMakeCache.txt not founf. Python paths checks skipped.")
return
# EBROOTPYTHON check
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And please remove this comment. It doesn't add any information to the code below

Copy link
Contributor

@Flamefire Flamefire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please recheck also the use(s) of self.log.error. When raising an EasyBuildError you don't need to log the same because that will already be done.
I also thing that you don't need self.log.error but only EasyBuildError, i.e. fail if there is an error.

Another enhancement would be to gather all issues (e.g. each wrong path) in a list and then fail if that list is non-empty. This way ALL issues would be reported, not only the first found which might help in fixing this.

python_prefixes = r"(Python|Python2|Python3)_"

for line in lines:
if line.startswith(python_prefixes + r"EXECUTABLE:FILEPATH="):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work. python_prefixes is all lowercase and you likely intended to use something like re.match. Got to look up the docs but from the top of my head: python_prefixes = "PYTHON[23]?_" above and re.match(python_prefixes + "EXECUTABLE(:FILEPATH)?=", line) here would be needed

python_library_path.append(line.split('=')[1].strip())
self.log.info("Python library path: %s", python_library_path[-1])

# Check if paths are found and validate paths for symlinks
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything from here should be outside the loop shouldn't it?


# Check if paths are found and handle EBROOTPYTHON cases
if any(path for path in [python_exec_path, python_include_path, python_library_path]):
if not os.getenv('EBROOTPYTHON'):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a duplication to the below (ebrootpython_path etc). Maybe at least put them together? Are both even required? I.e. isn't ebrootpython_path enough/better than EBROOTPYTHON?

)
elif not all(
(path and os.getenv('EBROOTPYTHON') in path)
for path in [python_exec_path, python_include_path, python_library_path]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are checking only for $EBROOTPYTHON being in a list of paths, which likely is always false. Maybe rename the variables to be able to spot that: python_exec_path -> python_exec_paths and so on.

It might even make sense to show which path is "wrong". I.e. which of the 3 lists and which exact path is outside EB.

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.

None yet

5 participants