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

cmake Python changes #2920

Merged
merged 12 commits into from
Jun 21, 2024
Merged

cmake Python changes #2920

merged 12 commits into from
Jun 21, 2024

Conversation

Lestropie
Copy link
Member

Closes #2730.

My third attempt at Python refactoring following cmake transition (#2689), after #2737 and #2741. Done a decent amount of thinking about it after it was last spoken about during a dev team meeting. I'm happy with this one and want to proceed. Commands all seem to execute as expected, from both build and install directories. For existing Python commands, requisite change is minimal; just deletion of the "import mrtrix3; mrtrix3.execute()" at the tail of the file.

Lots of details in commit message of 93f3741.

@daljit46: Handballing to you. You have carte blanche to change as you see fit; whether to resolve my cmake naivety, or anything in this proposal that would be completely prohibitive if trying to expand the concept to external project support. But in the absence of any major criticisms from yourself or any other @MRtrix3/mrtrix3-devs, hoping this gets me out of your way to proceed with #2901.

Lestropie and others added 3 commits June 9, 2024 19:23
- Re-arrange Python source files on the filesystem. API files reside in python/mrtrix3/ (still in a sub-directory called "mrtrix3/" so that IDEs can reasonably identify them, but no need to be in a "lib/" sub-directory in source form). All command source code centralised into python/mrtrix3/commands.
- cmake will generate short executable Python files in the build bin/ directory, one for each command. These load the version-matched API and command code from a relative path. This mechanism deprecates file python/bin/mrtrix3.py, and command source files no longer include the "import mrtrix3; mrtrix3.execute()" code at their tail.
- Change to the interface of the app._execute() function. Rather than a module, it now accepts as input the usage() and execute() functions. This should allow greater flexibility in how a developer arranges their command code.
- Following from point above, there are now three different ways for a developer to arrange their command code on the filesystem:
  1. A solitary .py file residing in python/mrtrix3/commands/, which defines both usage() and execute() functions within.
  2. A sub-directory residing in python/mrtrix3/commands/, which contains a .py file with the same name as the sub-directory, within which contains the usage() and execute() functions. This is useful for those commands using the "algorithm" concept, as each algorithm can be defined as its own .py file within that sub-directory; but all source code relating to that command is grouped within that directory.
  3. A sub-directory residing in python/mrtrix3/commands/, which contains at least two files called usage.py and execute.py, which provide the usage() and execute() function implementations respectively. This will be useful for those scripts where the volume of code is too much for a single source code file.
- mrtrix3.algorithm module deprecated. Some functionality is no longer required, and algorithm modules are now loaded directly using importlib instead. List of algorithms available for relevant commands is now explicitly coded in the corresponding __init__.py files.
- No longer have to rename source code relating to the 5ttgen command to "_5ttgen"; all handling of module names should now be permissive of leading digits.
- cmake can either copy or softlink Python source code files, toggled via envvar "MRTRIX_PYTHON_SOFTLINK".
- Deprecate commands blend, convert_bruker, gen_scheme, notfound; commands not utilising the MRtrix3 Python API are not well managed by the new build system, and still do not appear in the online documentation, so will need to be either ported or provided externally.
- Files python/mrtrix3/version.py.in and python/mrtrix3/commands/__init__.py.in generate build directory files lib/mrtrix3/version.py and lib/mrtrix3/commands/__init__.py, filled with relevant build-time information. However files python/mrtrix3/version.py and python/mrtrix3/commands/__init__.py are still defined in the source tree, with the relevant variables defined, only that they are void of information. This allows run_pylint to run without even configuring cmake, and should prevent IDEs from producing undefined symbol warnings.
Copy link

github-actions bot commented Jun 9, 2024

clang-tidy review says "All clean, LGTM! 👍"

Copy link

github-actions bot commented Jun 9, 2024

clang-tidy review says "All clean, LGTM! 👍"

@Lestropie
Copy link
Member Author

  • For Python-API-based testing tools, need to have cmake generate executables just as is done for Python commands.

CMAKE_SOURCE_DIR refers to the top level source tree. Hence, if mrtrix3
is built as a subproject of another project (e.g. using
add_subdirectory), things won't work as expected.
@daljit46
Copy link
Member

Looks mostly fine to me at a first glance.

API files reside in python/mrtrix3/ (still in a sub-directory called "mrtrix3/" so that IDEs can reasonably identify them, but no need to be in a "lib/" sub-directory in source form).

I don't quite the reasoning behind this. How does this help IDEs?

Copy link

clang-tidy review says "All clean, LGTM! 👍"

@Lestropie
Copy link
Member Author

I don't quite the reasoning behind this. How does this help IDEs?

Not actually tested, but I assume that if an IDE sees from mrtrix3 import app, and you try to hotkey from function invocation to declaration, that is far more likely to succeed if file "app.py" resides in a directory called "mrtrix3/"; hence putting those files in python/mrtrix3/ rather than python/.

@daljit46
Copy link
Member

I see, that makes sense. Just tested this on VS Code and it behaves as you predicted.

@daljit46 daljit46 force-pushed the cmake_python_changes branch 2 times, most recently from cfe7d0c to 648468f Compare June 13, 2024 12:19
@daljit46
Copy link
Member

daljit46 commented Jun 13, 2024

I think it would make sense for cmake/MakePythonExecutable.cmake to accept a DESTINATION_PATH (or an OUTPUT_DIR) argument instead of BUILDDIR. This way we can use the logic in the script for testing tools or elsewhere.

Copy link

clang-tidy review says "All clean, LGTM! 👍"

@daljit46
Copy link
Member

daljit46 commented Jun 14, 2024

I'm a little unsure on how to handle testing_python_cli. Currently, it resides in testing/tools, but I think this is not the appropriate location for it. The command is not even a "tool", in the sense that it's not really used by multiple scripts/executables to verify the correctness of input/outputs for a given command. Instead, it's just a "fake" python command used to test that the CLI works as intended.

Furthermore, currently we create the testing tools in ${PROJECT_BINARY_DIR}/testing/tools (which is added to PATH for any bash test invocation), but perhaps it makes sense to set their build output directory to ${PROJECT_BINARY_DIR}/bin. This has the benefit that whatever mechanism we use for standard Python commands should, in theory, also work for executing a testing tool.

Copy link

clang-tidy review says "All clean, LGTM! 👍"

@Lestropie
Copy link
Member Author

RE testing_python_cli:

  • If it were the case that our CMakeLists didn't involve globbing, then that file could happily reside in python/mrtrix3/commands/, and just be omitted from the list of generated executables if not building tests. I'm not sure if this case is sufficient to make that transition, just making the observation.
  • While it's true that the number of tests that invoke this command is only 1, I'm not sure if that distinction is adequate to motivate conceptualising it differently to the other testing tools. It is nevertheless still "a tool that is invoked exclusively by tests".

RE the build path for testing tools, personally I find it a little unusual to look inside of the bin/ directory and see commands in there that are exclusively for testing. Eg. There's a command called to. So if anything I'd prefer to be moving those "unit test" test commands out of bin/ and into testing/tools/, rather than moving anything in the opposite direction.

This directs IDEs like Qt Creator to show the Python code as project
files.
- Instead of specifying a BUILDDIR, the caller must specify an OUTPUT_DIR directory where the output file will be written.
- The script now additionally accepts a list of directories that will be prepended to the system path in the generated script. This shouldn't be necessary for most commands.
- Executables for Python testing tools which are essentially MRtrix3
Python commands (e.g. they are defined by a usage and run function), are
generated using the MakePythonExecutable script.

- Additionally, some renaming of variables has been performed for
consistency.
Copy link

clang-tidy review says "All clean, LGTM! 👍"

1 similar comment
Copy link

clang-tidy review says "All clean, LGTM! 👍"

@daljit46
Copy link
Member

I have made some changes to fix the running of unit tests. cmake/MakePythonExecutable.cmake now accepts an OUTPUT_DIR directory where the output executable will be generated, and also takes an optional list EXTRA_PATH_DIRS that can be used to specify additional paths to be prepended to sys.path.
In testing/tools/CMakeLists.txt, now there is a new function add_python_tool which can generate a Python test executable that behaves like a standard MRtrix3 python command (using MakePythonExecutable.cmake). This is a slightly cumbersome approach, but it does seem to work.
@Lestropie any feedback welcome.

Copy link

clang-tidy review says "All clean, LGTM! 👍"

Copy link

clang-tidy review says "All clean, LGTM! 👍"

@Lestropie
Copy link
Member Author

Lestropie commented Jun 21, 2024

Yep, that solution for testing_python_cli looks exactly like what I had in mind.

Python command documentation generation is failing on Linux CI:
find: '/home/runner/work/mrtrix3/mrtrix3/python/bin/': No such file or directory
Is this maybe a cache problem? The workflow makes no reference to that deprecated location.

Once that's resolved I'm happy for this to be merged.

Edit: Was docs/generate_user_docs.sh, not build cache.

Copy link

clang-tidy review says "All clean, LGTM! 👍"

1 similar comment
Copy link

clang-tidy review says "All clean, LGTM! 👍"

- Fix importlib call in cmake-generated Python executables for stand-alone Python files; this regressed in cleanup commit 291a747, which worked for the Python CLI test (as both executable and source file resided in the same directory) but broke execution of other Python commands.
- Change handling of Python CLI test: executable will be placed in ${PROJECT_BINARY_DIR}/bin; source code will be placed in ${PROJECT_BUILD_DIR}/lib/mrtrix3/commands/.
- Update docs/generate_user_docs.sh to reflect new handling of Python commands.
- Auto-update of some Python command help pages to propagate prior changes.
- Add per-test labels to unit tests.
Copy link

clang-tidy review says "All clean, LGTM! 👍"

@Lestropie
Copy link
Member Author

Spoke too soon; one of the changes you made to the cmake-generated Python executables to facilitate testing_python_cli broke the execution of some of the Python commands.

Full details in 3fce648, but what I chose to do is put testing_python_cli.py into ${PROJECT_BINARY_DIR}/lib/mrtrix3/commands/ alongside the other command source code, and generate the executable in ${PROJECT_BINARY_DIR}/bin; that way the same logic for the executable file generation applies.

See if you're happy with that. Assuming there isn't anything outstanding still broken, I'm happy to proceed with merging.

@daljit46 daljit46 merged commit 561dd2d into dev Jun 21, 2024
6 checks passed
@daljit46 daljit46 deleted the cmake_python_changes branch June 21, 2024 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants