python: simple addition to simplify importing MRtrix3 libraries#1613
python: simple addition to simplify importing MRtrix3 libraries#1613jdtournier merged 32 commits intodevfrom
Conversation
With this proposal, the code used to locate the MRtrix3 libraries is
shifted into a python file (tentatively called bin/__locate_mrtrix3.py)
in the bin/ folder, and applications only need to invoke:
import __locate_mrtrix3
from mrtrix3 import app
app.execute
|
I'm a big fan of any efforts to simplify this matter. Your commit looks OK to me, but best to wait for TravisCI to confirm.
I would not quite go that far (as you said too), but I would advocate making it a true "gateway" module that also imports the relevant elements of The file added at the end. |
Similar to other files.
|
Added |
- Do more checks in attempts to locate MRtrix3 Python modules - Wrap import of this module in a try clause so that external scripts can be executed without deletion of this line. - Move revised description of execution of external Python scripts from FAQ page to external modules page.
I have to admit, I'm not sure how Python handles these things. All these commands ran fine on my system, but for some weird reason Anyway, it's easily fixed, as done in c45185a - but I'm none the wiser as to how this actually works.
Sounds like a good idea. I assume you've tested it and it works...? Whether to go along with that is a decision I'll leave up to the heavy Python users. As long as there's a simple one-liner that can be used instead of that bulky chunk of code... |
Not yet, but it's easy to do. I'll give it a crack if there are no a priori objections.
Yes, that would be a nice addition, although of the options listed, I think the first one (checking for The other options could lead to conflicts with multiple installed versions, for instance a master-build in the PATH with the module linked to a current dev-build in a different folder. |
…ix3 into python_clean_locate_mrtrix3 Conflicts: bin/5ttgen bin/dwi2response bin/dwibiascorrect bin/dwigradcheck bin/dwinormalise bin/dwipreproc bin/dwishellmath bin/foreach bin/labelsgmfix bin/population_template bin/responsemean
|
I've never been able to figure out a way of doing this that I'm completely happy with. A few changes:
Would be worth adding I think; gives slightly better guarantee of software version matching than the above.
I don't think that provides any benefit over setting
I'm not at all familiar with the use of Python in this way; my only experience is with my own modules. If you can make a modification that makes this library and its usage "more like others", go for it: I simply don't know what that is. |
|
Proposed precedence for adding appropriate
|
|
At the risk of confusing matters further... I've just had a quick look into using the Basic idea: add a tiny 'module' file called
|
Very cool, I really like this solution. As you say, it appears to check all the boxes, and makes for a very clean interface in the scripts. Can you go ahead and commit your proposal so we can test it?
Personally, I don't think checking whether |
OK, done. But I've not deleted the
I'm in two minds about this. We'd need to either copy or symlink this file over to reside alongside any additional scripts anyway. But the |
|
I quite like the symlink of To avoid users setting up two symlinks to possibly conflicting versions, @dchristiaens suggested instructing users to only symlink |
|
Changes in c755207 work for me for a range of different scenarios, & on a Windows machine too. You can see the ordering of different tests and the logic behind them in the file. Before merging, I would suggest that the "External modules" documentation should be updated to reflect this as much as possible. I'm also wondering given these changes whether it should still be necessary to do: , or whether it would be possible for a " (Note: From prior testing, the relevant |
- Silence pylint warnings arising from parsing of the helper script rather than the modules themselves. - Alter syntax for invoking the app.execute() function. - pylint: Don't run for bin/__pycache__/.
- Fix non-testing of contents of bin/ directory in run_pylint. - Instruct python to ignore warnings related to the new trickery of "import mrtrix3". - population_template: Move import commands to inside functions in order to support new module loading mechanism.
This script will now only attempt to load the MRtrix3 Python libraries using two approaches: - Relative path to itself, after having traversed any softlinks. Relative path to build script after having traversed any softlinks.
|
I'm still slightly undecided on the " What I'm wondering instead is if those functionalities within I'd probably need to give this a go in order to figure out whether or not it would work sensibly. And it would mean another additional module file, which may be frowned upon. And " |
|
My 2 pence: Having an import statement of the library or parts thereof execute the script is surprising (ok, I meant not pythonic, makes me shiver). Having a single line About looking for the python library location: I'd vote for links to Checking PYTHONPATH feels unnecessary unless setting and following links is a pain (windows?) but not too fussed about that one as long as symlinks override PYTHONPATH. A limitation of relying on path variables is that if one wanted to call a script from within a script via run.command, one could use different library versions for the outer and inner script using links. To achieve the same via PATH variables would require passing environments to subprocess calls and hardcoding these into scripts. I'd warn if PYTHONPATH is used and in any case, if the python and c++ library versions do not match. |
I have the exact same feeling. An Regarding the library localisation, I think we just need a sensible default and leave everything else up to the user or module developer. I don't mind if you want to use the path of |
|
OK, more thoughts... I see you've removed the fall-back mechanisms of looking through I also think executing the script upon import is very unexpected. I'd much rather stick to an explicit one-liner that very clearly say what it does - and importantly at what point in the script. Just to add to the discussion: there is a potential problem on the Windows side given the difficulties in creating symbolic links. It's possible, but not trivial, and likely to complicate deployment of modules in the future. So I've had a quick look into alternatives, as least for the This basically sorts out the lack of shortcut support on Windows, with a simpler approach than we're currently advocating, I reckon. For |
Following discussion in #1613. Partly revert aa495aa: No longer execute using a simple "import" call, but move the principal execute() function to __init__.py; this means that the mrtrix3.app module can be imported in a similar fashion to all other modules, rather than requiring special treatment due to being imported in the outermost code loop.
This module can be a collection point for functions or classes that are of utility but don't sensibly fit into any of the other named modules.
|
I think I've got the right compromise with respect to the So the "
I'm not sure about issuing a warning: If the environment variable has been set, the user has made an explicit intervention to do so; the only criticism is that it is a less robust approach than softlinking
Yes, I should have a go at that. |
Actually, not sure if anything can be done here: The version number within Python is set by the |
This supports the case where the build script in a module is not a symbolic link, but a regular text file containing a single line with the location of the build script.
|
OK, I've just added support for using a text file containing the path to the build script in the module loading, and updated the docs to match. I reckon it's good to go... |
Lestropie
left a comment
There was a problem hiding this comment.
Quick test of having a single line path as the contents of file build worked on my Windows machine. Had to update dwicat based on changes in this branch to pass CI. Overall I think we've converged on a decent solution.
With this proposal, the code used to locate the MRtrix3 libraries is shifted into a python file (tentatively called
bin/__locate_mrtrix3.py) in thebin/folder, and applications only need to invoke:This could be simplified further by renaming
__locate_mrtrix3.pytorun_mrtrix3.pyor something, and have that file also contain theapp.execute()call. But that would preclude its use in other modules - not sure it's a big loss anyway, since modules would reside in other locations and so couldn't use this directly anyway.Another potential addition would be to extend this file with functionality to operate from 3rd party modules. So all they'd need is to copy/paste it into their modules, and then we could offer a range of options to identify the MRtrix3 libraries:
buildsymlink exists and follow that if foundmrinfoormrconvertin thePATH, and use their path to locate the correspondinglib/folderMRTRIX_ROOT_DIRor something to locate the librariesNone of these would be foolproof, but they'd at least allow external module operation without modifying the PYTHON_PATH, which might be desirable... (?)