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

38882 gsas2scriptable path search revision #38976

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

JackEAllen
Copy link
Contributor

@JackEAllen JackEAllen commented Feb 25, 2025

Description of work

Summary of work

Dynamically search for GSASIIscriptable.py from outer most parent library of GSAS-II using a recursive directory search with a depth limit of 3 set to avoid searching too deeply into a given directory structure.

Improve error message return descriptions where:

  • GSASIIscriptable.py is not found.
  • GSASIIscriptable.py has been found, but an import error occurred.
  • Python binaries could not been found in /gsas2_parent_dir/GSAS-II/bin/python

The location of GSASIIscriptable.py is not consistent across different versions of GSAS-II. For newer version of GSAS-II (5758 or later), GSASIIscriptable.py is not correctly located

Fixes #38882

Further detail of work

Mantid anaconda label: new_gsas_path_search_test - PLEASE REMOVE LABEL FROM ANACONDA ONCE PR IS APPROVED.

To test:

Testing with newer versions of GSAS-II:

  1. Install a newer version of GSAS-II such as version 5758 or later.
  2. Checkout the main branch: git switch main && git fetch && git pull
  3. Launch workbench from CLI workbench and follow the Engineering Diffraction Test 11
  4. Notice that if the path is set to the outer most directory of GSAS-II, you will receive an error similar to:
GSAS-II call failed with error: Traceback (most recent call last):
  File "/mantidproject/mantid/qt/python/mantidqtinterfaces/mantidqtinterfaces/Engineering/gui/engineering_diffraction/tabs/gsas2/call_G2sc.py", line 195, in main
    import GSASIIscriptable as G2sc
ModuleNotFoundError: No module named 'GSASIIscriptable'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/mantidproject/mantid/qt/python/mantidqtinterfaces/mantidqtinterfaces/Engineering/gui/engineering_diffraction/tabs/gsas2/call_G2sc.py", line 232, in <module>
    main()
  File "/mantidproject/mantid/qt/python/mantidqtinterfaces/mantidqtinterfaces/Engineering/gui/engineering_diffraction/tabs/gsas2/call_G2sc.py", line 197, in main
    raise ImportError(f"GSAS-II was not found at {import_path}")
ImportError: GSAS-II was not found at /gsas2/GSASII
  1. If the path is intuitively set closer to GSASIIscriptable.py, maybe gsas2/GSAS-II, you will receive an similar error to:
GSAS-II call failed with error: [Errno 2] No such file or directory: '/gsas2/GSAS-II/bin/python'. Please check the Path to GSASII in the Engineering Diffraction Settings is valid
  1. Switch to the the PR branch: git switch 38882_gsas2scriptable_path_search_revision
  2. Repeat steps 3-5, and notice that the error for step 4 GSAS should now load correctly. For step 5, notice that the same error will be returned with the additional statement: Path must be outer most directory of GSAS-II installation. This message should better aid a user to the directory needed for GSAS-II to load correctly.
  3. Move the GSASIIscriptable.py to another directory within the GSAS library such as directly under the parent folder. the rough location of GSASIIscriptable.py from the parent directory of the library will be: /gsas2/GSAS-II/GSASII/GSASIIscriptable.py for newer versions of GSAS-II
  4. On the GSAS II tab in the Engineering Diffraction interface, click refine after following step 3. You should receive an import error that specified that GSASIIscriptable.pyhas been found, but an import error occurred similar to:
 File "/mantidproject/mantid/qt/python/mantidqtinterfaces/mantidqtinterfaces/Engineering/gui/engineering_diffraction/tabs/gsas2/call_G2sc.py", line 200, in find_gsasii
   raise ImportError(
ImportError: GSASIIscriptable (GSASIIscriptable.py) module found in /gsas2 but could not be imported
  1. Move the GSASIIscriptable.py back to it's original location: ~/gsas2/GSAS-II/GSASII/GSASIIscriptable.py

Testing with older versions of GSAS-II:

  1. Login to IDAaaS and create a new EnginX workspace.
  2. Check the version of GSAS in the workspace is 4579. This can be checked before launching the workspace by clicking on the setting cog at the top right of the workspace under the "Included Software" subheading.
  3. Launch the EnginX workspace.
  4. Open a terminal Applications >> System >> Terminal
  5. Execute the following command:
mamba create -n mantid-test -c mantid/label/new_gsas_path_search_test -c mantid/label/nightly mantidworkbench

-c mantid/label/nightly is required due to a an mslice version being pinned which will prevent you from creating a valid environment otherwise.
6. Activate your environment mamba activate mantid-test and open workbench workbench from the CLI.
7. Repeat steps 3-5, from "Testing with newer versions of GSAS-II" and notice the update error messages, mentioned in step 7.


Reviewer

Please comment on the points listed below (full description).
Your comments will be used as part of the gatekeeper process, so please comment clearly on what you have checked during your review. If changes are made to the PR during the review process then your final comment will be the most important for gatekeepers. In this comment you should make it clear why any earlier review is still valid, or confirm that all requested changes have been addressed.

Code Review

  • Is the code of an acceptable quality?
  • Does the code conform to the coding standards?
  • Are the unit tests small and test the class in isolation?
  • If there is GUI work does it follow the GUI standards?
  • If there are changes in the release notes then do they describe the changes appropriately?
  • Do the release notes conform to the release notes guide?

Functional Tests

  • Do changes function as described? Add comments below that describe the tests performed?
  • Do the changes handle unexpected situations, e.g. bad input?
  • Has the relevant (user and developer) documentation been added/updated?

Does everything look good? Mark the review as Approve. A member of @mantidproject/gatekeepers will take care of it.

Gatekeeper

If you need to request changes to a PR then please add a comment and set the review status to "Request changes". This will stop the PR from showing up in the list for other gatekeepers.

@JackEAllen JackEAllen added Diffraction Issues and pull requests related to diffraction Powder Issues and pull requests related to powder diffraction ISIS Team: Diffraction Issue and pull requests managed by the Diffraction subteam at ISIS labels Feb 25, 2025
@JackEAllen JackEAllen added this to the Release 6.13 milestone Feb 25, 2025
Create custom implementation of rglob with the method name limited_rglob to recursively search a directory tree structure for a given filename. limited_rglob allows for the setting of a max depth value to limit how deep the directory tree structure is searched to avoid searching uneccesarily deep which could be time-consuming and recourse intensive depening on the path provided
Replace previous approach which directly set the import path and attempted to import the module with a more robust and dynamic approach. Replacing the previous implementation with find_gsasii allows for controlled depth resursive searching of sub-directories for GSASIIscriptable and does not rely on hard-coded paths which may change across versions of GSAS-II. Moving the previous approach into find_gsasii improves error handling and error visibility by providing more detailed errors which will help diagnose if GSASIIscriptable has been found and there is an import error or if GSASIIscriptable could not be found.
Improve error description when searching for GSASII binaries if they cannot be found. It is not inherently obvious that the outer most parent path of the GSASII installation is required in the settings panel for the model as only GSASIIscriptable is required to import GSAS in call_G2sc.py. The improved error message tells the user where they should set the path too rather than assuming
@JackEAllen JackEAllen force-pushed the 38882_gsas2scriptable_path_search_revision branch from 04e9742 to a251cce Compare March 4, 2025 14:25
@JackEAllen JackEAllen marked this pull request as ready for review March 5, 2025 11:57
@RichardWaiteSTFC RichardWaiteSTFC self-assigned this Mar 6, 2025
Copy link
Contributor

@RichardWaiteSTFC RichardWaiteSTFC left a comment

Choose a reason for hiding this comment

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

This is a big improvement thanks for doing this! I have tested on windows with a newer version and everything works great and the error messages are a lot more helpful.

I have yet to test on IDAaaS as they seem to have network issues, in the meantime I have a minor suggestion for the release note. Also what do you think about adding a unit test?

@@ -0,0 +1 @@
- `#38882 <https://github.com/mantidproject/mantid/issues/38882>`_ : Fix issue with ``GSAS-II GSASIIscriptable.py`` hard-coded path which is invalid for newer version of GSAS-II.
Copy link
Contributor

@RichardWaiteSTFC RichardWaiteSTFC Mar 7, 2025

Choose a reason for hiding this comment

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

Probably worth adding a version number which we know doesn't work on main? Just so people get a feel for what newer versions of GSAS-II means?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point! There may be other older versions of GSAS-II between the one installed on IDAaaS (4579) and the most recent version I have tested with (5758) that may also cause a path issue prior to this PR that I'm not aware of, however we should specify at least one known version that breaks on main currently. I will update the release notes to include the newest version of GSAS-II 5758 that this PR aims to resolve.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep I think there's no point going through GSAS github trying to find out when the directory changes, but agreed, if you could add that it will now work for version 5758 as you suggest - that would be great thanks!

@@ -164,6 +168,41 @@ def export_lattice_parameters(temp_save_directory, name_of_project, project):
file.write(parameters_json)


def limited_rglob(directory: Path, pattern: str, max_depth: int) -> Generator[Path, None, None]:
Copy link
Contributor

Choose a reason for hiding this comment

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

Technically this could have a unit test associate with it in test_call_G2sc.py - perhaps setting up a temp directory that reflects the old and new GSAS version setup? But that might be overkill - what do you think?

Don't worry about making any changes as this seems to work well. However, it occurred to me the logic in this function is quite complicated for what it is doing (but maybe I'm not grasping all the subtleties)!

For example on L177

if depth >= max_depth:
            dirs[:] = []  # Max depth reached, don't recurse further

Is there any reason one couldn't break here and return the appropriate null path (anything that isn't a file I think)?
Could depth instead just be a counter and do depth += 1 instead of depth = root[len(str(directory)) + len(os.path.sep) :].count(os.path.sep) + 1 etc.?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Using break would exit the loop entirely, which might mean we don't find the file we are searching for if there are other directories at the same level to process.

By using dirs[:] = [], we ensure that the traversal stops at the current directory level without affecting the parent directory's traversal if there are other directories at at the same level. This approach basically future proofs against the path ever changes again.

Using depth = root[len(str(directory)) + len(os.path.sep) :].count(os.path.sep) + 1 will have the downside of being more complicated compared to using a counter due to the usage of string slicing and counting separators, but will be more accurate.
The depth is recalculated based on the actual path, ensuring it accurately reflects the directory structure which will be resilient against the directory structure possibly changing during execution (though this is very unlikely). The main benefit is that this will also handle edge cases where directories might be skipped or have varying depths.

I agree that this method is likely too complicated for just the case of searching for GSASIIscriptable.py.
My plan is to potentially move this method out of engineering_diffraction/tabs/gsas2/call_G2sc.py and into engineering_diffraction/tabs/gsas2/model.py as part of a larger refactor and use the same method to also search for the python binaries which are searched for within mantid/qt/python/mantidqtinterfaces/mantidqtinterfaces/Engineering/gui/engineering_diffraction/tabs/gsas2/model.py.call_subprocess to protect against possible being moved elsewhere within the GSAS-II package.

Copy link
Contributor Author

@JackEAllen JackEAllen Mar 7, 2025

Choose a reason for hiding this comment

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

Though adding a test could be considered overkill as path searching errors will be caught elsewhere when searching for GSASIIscriptable.py I believe you're right to suggest adding a test. Thank you for catching this!

I'll work on adding a test to check a variety of different directory structures as this will also be a useful test to have for when this method is possibly moved into mantid/qt/python/mantidqtinterfaces/mantidqtinterfaces/Engineering/gui/engineering_diffraction/tabs/gsas2/model.py

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for adding a test!
RE logic/counters etc. - I didn't mean drag and drop the counter etc. into the current logic. I know it would require different ifs and loops etc. To be clear I'm not suggesting you change what you have! Also I hadn't thought of the directory changing mid-execution - a good point!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll refresh the review once I've added a test 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Diffraction Issues and pull requests related to diffraction ISIS Team: Diffraction Issue and pull requests managed by the Diffraction subteam at ISIS Powder Issues and pull requests related to powder diffraction
Projects
Status: In Review
Development

Successfully merging this pull request may close these issues.

GSASIIscriptable Path is Not Correctly Located For Newer Versions of GSAS-II
2 participants