From 73004d0963c089b86ba37753622a745552abd188 Mon Sep 17 00:00:00 2001 From: Piotr Rozyczko Date: Wed, 17 Nov 2021 09:53:31 +0100 Subject: [PATCH 01/10] Develop branch updated with necessary fixes --- .../Components/UserTutorialsController.qml | 30 +++++++++---------- pyproject.toml | 1 + tools/Scripts/FreezeApp.py | 20 +++++++++++++ 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/easyDiffractionApp/Gui/Components/UserTutorialsController.qml b/easyDiffractionApp/Gui/Components/UserTutorialsController.qml index 915e46e9..48df66b8 100644 --- a/easyDiffractionApp/Gui/Components/UserTutorialsController.qml +++ b/easyDiffractionApp/Gui/Components/UserTutorialsController.qml @@ -131,11 +131,11 @@ EaElements.RemoteController { rc.mouseClick(ExGlobals.Variables.preferencesButton) if (!was_tool_tips_checked) { rc.mouseClick(ExGlobals.Variables.enableToolTipsCheckBox) - rc.wait(500) + rc.wait(1000) } if (!was_user_guides_checked) { rc.mouseClick(ExGlobals.Variables.enableUserGuidesCheckBox) - rc.wait(500) + rc.wait(1000) } rc.mouseClick(ExGlobals.Variables.preferencesOkButton) } @@ -165,7 +165,7 @@ EaElements.RemoteController { playPageUserGuides(EaGlobals.Variables.SummaryPageIndex) if (!was_user_guides_checked) { rc.mouseClick(ExGlobals.Variables.userGuidesLastDisableButton) - rc.wait(500) + rc.wait(2000) } // Restore app preferences @@ -205,12 +205,12 @@ EaElements.RemoteController { if (!was_tool_tips_checked) { rc.mouseClick(ExGlobals.Variables.enableToolTipsCheckBox) - rc.wait(500) + rc.wait(2000) } if (was_user_guides_checked) { rc.mouseClick(ExGlobals.Variables.enableUserGuidesCheckBox) - rc.wait(500) + rc.wait(2000) } rc.mouseClick(ExGlobals.Variables.preferencesOkButton) @@ -266,7 +266,7 @@ EaElements.RemoteController { rc.mouseClick(ExGlobals.Variables.zProjectionButton) rc.mouseClick(ExGlobals.Variables.defaultViewButton) - rc.wait(1000) + rc.wait(5000) // Experiment Tab @@ -280,7 +280,7 @@ EaElements.RemoteController { rc.say("Now, you can switch to the analysis page to see and control the simulated diffraction pattern.") rc.mouseClick(ExGlobals.Variables.analysisTabButton) - rc.wait(1000) + rc.wait(3000) rc.say("In the advanced controls, you can choose between different calculation engines.") rc.mouseClick(ExGlobals.Variables.analysisAdvancedControlsTabButton) rc.mouseClick(ExGlobals.Variables.calculatorsGroup, 15) @@ -289,13 +289,13 @@ EaElements.RemoteController { x_pos = undefined y_pos = EaStyle.Sizes.comboBoxHeight * 1.5 rc.mouseClick(ExGlobals.Variables.calculatorSelector, x_pos, y_pos) - rc.wait(1000) + rc.wait(5000) // GSAS-II rc.mouseClick(ExGlobals.Variables.calculatorSelector) x_pos = undefined y_pos = EaStyle.Sizes.comboBoxHeight * 2.5 rc.mouseClick(ExGlobals.Variables.calculatorSelector, x_pos, y_pos) - rc.wait(1000) + rc.wait(5000) // CrysPy rc.mouseClick(ExGlobals.Variables.calculatorSelector) rc.mouseClick(ExGlobals.Variables.calculatorSelector) @@ -305,7 +305,7 @@ EaElements.RemoteController { rc.say("Now, you can see the interactive report generated on the summary page and export it in different formats.") rc.mouseClick(ExGlobals.Variables.summaryTabButton) - rc.wait(1000) + rc.wait(2000) //rc.pointerMove(ExGlobals.Variables.reportWebView) //rc.mouseMove(ExGlobals.Variables.reportWebView) //rc.mouseWheel(ExGlobals.Variables.reportWebView) @@ -323,12 +323,12 @@ EaElements.RemoteController { if (!was_tool_tips_checked) { rc.mouseClick(ExGlobals.Variables.enableToolTipsCheckBox) - rc.wait(500) + rc.wait(2000) } if (was_user_guides_checked) { rc.mouseClick(ExGlobals.Variables.enableUserGuidesCheckBox) - rc.wait(500) + rc.wait(2000) } rc.mouseClick(ExGlobals.Variables.preferencesOkButton) @@ -388,7 +388,7 @@ EaElements.RemoteController { rc.typeText("0") rc.keyClick(Qt.Key_Enter) // DOESN'T WORK ON CI XVFB ? rc.mouseClick(ExGlobals.Variables.fitResolutionYCheckBox) - rc.wait(1000) + rc.wait(5000) rc.mouseClick(ExGlobals.Variables.startFittingButton) isPreparationToFitDone = true @@ -399,7 +399,7 @@ EaElements.RemoteController { function finishDataFittingTutorial() { print("* fitting finished") - rc.wait(1000) + rc.wait(2000) rc.mouseClick(ExGlobals.Variables.refinementResultsOkButton) rc.mouseClick(ExGlobals.Variables.summaryTabButton) @@ -408,7 +408,7 @@ EaElements.RemoteController { //rc.mouseClick(ExGlobals.Variables.saveConfirmationOkButton) // Reset app state - rc.wait(1000) + rc.wait(5000) rc.mouseClick(ExGlobals.Variables.resetStateButton) rc.mouseClick(ExGlobals.Variables.resetStateOkButton) diff --git a/pyproject.toml b/pyproject.toml index c39a734a..05bc9c89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -147,6 +147,7 @@ separator = { macos = ':', ubuntu = ':', windows = ';' } dir_suffix = { macos = '.app', ubuntu = '', windows = '' } content_suffix = { macos = 'Contents/MacOS/', ubuntu = '', windows = '' } libs = { macos = 'libsDarwin', ubuntu = 'libsLinux', windows = 'libsWin32' } +missing_calculator_libs = { macos = [], ubuntu = [], windows = ['GSASII.libs', 'CFML.libs'] } missing_pyside2_files = { macos = ['libshiboken2.abi3.*.dylib'], ubuntu = [], windows = ['shiboken2.abi3.dll', 'MSVCP140.dll'] } missing_pyside2_plugins = { macos = [], ubuntu = ['Qt/plugins/xcbglintegrations'], windows = [] } # EGL and GLX plugins missing_other_libraries = {macos = [], ubuntu = [], windows = ['libs/libiomp5md.dll', 'libs/opengl32.dll'] } diff --git a/tools/Scripts/FreezeApp.py b/tools/Scripts/FreezeApp.py index 3bfbfd5b..baff86ea 100755 --- a/tools/Scripts/FreezeApp.py +++ b/tools/Scripts/FreezeApp.py @@ -7,6 +7,7 @@ import os, sys import glob +import site import PySide2, shiboken2 import cryspy, GSASII import easyCore, easyDiffractionLib, easyApp @@ -43,6 +44,8 @@ def addedData(): for extra_file in extras: data.append({'from': extra_file, 'to': '.'}) + data = data + copyCalculators() + formatted = [] for element in data: formatted.append(f'--add-data={element["from"]}{separator}{element["to"]}') @@ -56,6 +59,23 @@ def appIcon(): icon_path = os.path.abspath(icon_path) return f'--icon={icon_path}' +def copyCalculators(): + missing_calculator_libs = CONFIG['ci']['pyinstaller']['missing_calculator_libs'][CONFIG.os] + data = [] + try: + message = 'Copy calculator libraries' + # use the last element, since on certain conda installations we get more than one entry + site_packages_path = site.getsitepackages()[-1] + for lib_name in missing_calculator_libs: + lib_path = os.path.join(site_packages_path, lib_name) + data.append({'from': lib_path, 'to': lib_name}) + except Exception as exception: + Functions.printFailMessage(message, exception) + sys.exit(1) + + Functions.printSuccessMessage(message) + return data + def copyMissingLibs(): missing_files = CONFIG['ci']['pyinstaller']['missing_pyside2_files'][CONFIG.os] if len(missing_files) == 0: From 1d4585d11f3bdf9de03b440ed38e4244b59159d3 Mon Sep 17 00:00:00 2001 From: Piotr Rozyczko Date: Wed, 17 Nov 2021 10:30:05 +0100 Subject: [PATCH 02/10] enabled tutorials on windows --- .github/workflows/build.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c42a8e24..a6b72922 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -108,11 +108,11 @@ jobs: Xvfb :0 -screen 0 1920x1080x24 -ac & echo "DISPLAY=:0" >> $GITHUB_ENV - - name: Set up screen recording dependencies (Windows) - if: runner.os == 'Windows' - run: | - Set-DisplayResolution -Width 1920 -Height 1080 -Force - Get-DisplayResolution + # - name: Set up screen recording dependencies (Windows) + # if: runner.os == 'Windows' + # run: | + # Set-DisplayResolution -Width 1920 -Height 1080 -Force + # Get-DisplayResolution - name: Make dir for .desktop file (Linux) if: runner.os == 'Linux' @@ -122,7 +122,6 @@ jobs: run: poetry run python ${{ env.SCRIPTS_PATH }}/InstallApp.py - name: Run app in testmode, record screen and quit - if: runner.os != 'Windows' run: poetry run python ${{ env.SCRIPTS_PATH }}/RunApp.py --testmode - name: Rename test videos From fd20bca955554e6f0197e97716b44dede60ba2f0 Mon Sep 17 00:00:00 2001 From: Piotr Rozyczko Date: Tue, 23 Nov 2021 10:51:37 +0100 Subject: [PATCH 03/10] check if get-DisplayResolution is working --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a6b72922..0ffbb9c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -108,11 +108,11 @@ jobs: Xvfb :0 -screen 0 1920x1080x24 -ac & echo "DISPLAY=:0" >> $GITHUB_ENV - # - name: Set up screen recording dependencies (Windows) - # if: runner.os == 'Windows' - # run: | - # Set-DisplayResolution -Width 1920 -Height 1080 -Force - # Get-DisplayResolution + - name: Set up screen recording dependencies (Windows) + if: runner.os == 'Windows' + run: | + Set-DisplayResolution -Width 1920 -Height 1080 -Force + Get-DisplayResolution - name: Make dir for .desktop file (Linux) if: runner.os == 'Linux' From 6f450bc5654d65639a0b82ff78ec9163a0110576 Mon Sep 17 00:00:00 2001 From: Piotr Rozyczko Date: Tue, 23 Nov 2021 11:30:47 +0100 Subject: [PATCH 04/10] Add return code to copyFile() for debugging purposes --- tools/Scripts/Functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Scripts/Functions.py b/tools/Scripts/Functions.py index 5acefa7a..02cc4295 100755 --- a/tools/Scripts/Functions.py +++ b/tools/Scripts/Functions.py @@ -171,7 +171,7 @@ def copyFile(source, destination): shutil.copy2(source, destination, follow_symlinks=True) except Exception as exception: printFailMessage(message, exception) - sys.exit() + sys.exit(1) else: printSuccessMessage(message) From ebfed987521e6db36414591fc9fda2a2407356d4 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Tue, 23 Nov 2021 12:46:39 +0100 Subject: [PATCH 05/10] Try pyinstaller 4.5.1 instead of 4.7 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 05bc9c89..d067192f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ easyApp = { git = 'https://github.com/easyScience/easyApp.git', rev = 'develop' #[tool.poetry.dev-dependencies] # PyInstaller -pyinstaller = '^4.5.1' +pyinstaller = '4.5.1' #pyinstaller = { git = 'https://github.com/pyinstaller/pyinstaller.git', rev = 'develop' } pywin32-ctypes = { version = '^0.2.0', platform = 'win32' } pypiwin32 = { version = '^223', platform = 'win32' } From c58fcb049787ca4a03efa6df11bb4a9eb6310f29 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Tue, 23 Nov 2021 13:04:42 +0100 Subject: [PATCH 06/10] Try pyinstaller 4.6 instead of 4.7 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d067192f..1c82503b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ easyApp = { git = 'https://github.com/easyScience/easyApp.git', rev = 'develop' #[tool.poetry.dev-dependencies] # PyInstaller -pyinstaller = '4.5.1' +pyinstaller = '4.6' # 4.7 gives "ModuleNotFoundError: No module named 'pip'" on Ubuntu, when run app #pyinstaller = { git = 'https://github.com/pyinstaller/pyinstaller.git', rev = 'develop' } pywin32-ctypes = { version = '^0.2.0', platform = 'win32' } pypiwin32 = { version = '^223', platform = 'win32' } From 40c6e007fef86b5b8d4fca444fe66991b92fc5d3 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Tue, 23 Nov 2021 13:27:30 +0100 Subject: [PATCH 07/10] Fix pyinstaller to be 4.5.1 as 4.6-4.7 failed on Ubuntu --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1c82503b..59fd18ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ url = "https://easyscience.github.io/pypi/" secondary = true [tool.poetry.dependencies] -python = '^3.7, <3.8' +python = '^3.7, <3.9' darkdetect = '^0.3.1' pyobjc-core = { version = '^7.1', platform = 'darwin' } pyobjc-framework-cocoa = { version = '^7.1', platform = 'darwin' } @@ -33,7 +33,7 @@ easyApp = { git = 'https://github.com/easyScience/easyApp.git', rev = 'develop' #[tool.poetry.dev-dependencies] # PyInstaller -pyinstaller = '4.6' # 4.7 gives "ModuleNotFoundError: No module named 'pip'" on Ubuntu, when run app +pyinstaller = '4.5.1' # 4.6-4.7 give "ModuleNotFoundError: No module named 'pip'" on Ubuntu, when run app #pyinstaller = { git = 'https://github.com/pyinstaller/pyinstaller.git', rev = 'develop' } pywin32-ctypes = { version = '^0.2.0', platform = 'win32' } pypiwin32 = { version = '^223', platform = 'win32' } From d515296a3eb82fdae048014b74089d74d9989cd6 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Tue, 23 Nov 2021 13:28:22 +0100 Subject: [PATCH 08/10] Use python 3.8 instead of 3.7 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0ffbb9c6..1fc00370 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,7 +34,7 @@ jobs: - name: Set up Python environment uses: actions/setup-python@v2 with: - python-version: 3.7 + python-version: 3.8 - name: Upgrade PIP run: python -m pip install --upgrade pip From 591df9e12ed781ea3298c472da459c7254fee1cb Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Tue, 23 Nov 2021 14:30:16 +0100 Subject: [PATCH 09/10] Refactor addedData() --- tools/Scripts/FreezeApp.py | 98 +++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 54 deletions(-) diff --git a/tools/Scripts/FreezeApp.py b/tools/Scripts/FreezeApp.py index baff86ea..07f2ff23 100755 --- a/tools/Scripts/FreezeApp.py +++ b/tools/Scripts/FreezeApp.py @@ -17,6 +17,14 @@ CONFIG = Config.Config() +def appIcon(): + icon_dir = os.path.join(*CONFIG['ci']['app']['icon']['dir']) + icon_name = CONFIG['ci']['app']['icon']['file_name'] + icon_ext = CONFIG['ci']['app']['icon']['file_ext'][CONFIG.os] + icon_path = os.path.join(CONFIG.package_name, icon_dir, f'{icon_name}{icon_ext}') + icon_path = os.path.abspath(icon_path) + return f'--icon={icon_path}' + def excludedModules(): os_independent = CONFIG['ci']['pyinstaller']['auto_exclude']['all'] os_dependent = CONFIG['ci']['pyinstaller']['auto_exclude'][CONFIG.os] @@ -30,7 +38,7 @@ def excludedModules(): return formatted def addedData(): - separator = CONFIG['ci']['pyinstaller']['separator'][CONFIG.os] + # Add main data data = [{'from': CONFIG.package_name, 'to': CONFIG.package_name}, {'from': cryspy.__path__[0], 'to': 'cryspy'}, {'from': GSASII.__path__[0], 'to': '.'}, @@ -39,42 +47,24 @@ def addedData(): {'from': easyApp.__path__[0], 'to': 'easyApp'}, {'from': 'utils.py', 'to': '.'}, {'from': 'pyproject.toml', 'to': '.'}] - extras = CONFIG['ci']['pyinstaller']['missing_other_libraries'][CONFIG.os] - if extras: - for extra_file in extras: - data.append({'from': extra_file, 'to': '.'}) - - data = data + copyCalculators() - - formatted = [] - for element in data: - formatted.append(f'--add-data={element["from"]}{separator}{element["to"]}') - return formatted - -def appIcon(): - icon_dir = os.path.join(*CONFIG['ci']['app']['icon']['dir']) - icon_name = CONFIG['ci']['app']['icon']['file_name'] - icon_ext = CONFIG['ci']['app']['icon']['file_ext'][CONFIG.os] - icon_path = os.path.join(CONFIG.package_name, icon_dir, f'{icon_name}{icon_ext}') - icon_path = os.path.abspath(icon_path) - return f'--icon={icon_path}' - -def copyCalculators(): + # Add other missing libs + missing_other_libraries = CONFIG['ci']['pyinstaller']['missing_other_libraries'][CONFIG.os] + if missing_other_libraries: + for lib_file in missing_other_libraries: + data.append({'from': lib_file, 'to': '.'}) + # Add missing calculator libs + site_packages_path = site.getsitepackages()[-1] # use the last element, since on certain conda installations we get more than one entry missing_calculator_libs = CONFIG['ci']['pyinstaller']['missing_calculator_libs'][CONFIG.os] - data = [] - try: - message = 'Copy calculator libraries' - # use the last element, since on certain conda installations we get more than one entry - site_packages_path = site.getsitepackages()[-1] + if missing_calculator_libs: for lib_name in missing_calculator_libs: lib_path = os.path.join(site_packages_path, lib_name) data.append({'from': lib_path, 'to': lib_name}) - except Exception as exception: - Functions.printFailMessage(message, exception) - sys.exit(1) - - Functions.printSuccessMessage(message) - return data + # Format for pyinstaller + separator = CONFIG['ci']['pyinstaller']['separator'][CONFIG.os] + formatted = [] + for element in data: + formatted.append(f'--add-data={element["from"]}{separator}{element["to"]}') + return formatted def copyMissingLibs(): missing_files = CONFIG['ci']['pyinstaller']['missing_pyside2_files'][CONFIG.os] @@ -115,6 +105,26 @@ def copyMissingPlugins(): else: Functions.printSuccessMessage(message) +def excludeFiles(): + file_names = CONFIG['ci']['pyinstaller']['manual_exclude'] + if len(file_names) == 0: + Functions.printNeutralMessage(f'No libraries to be excluded for {CONFIG.os}') + return + try: + message = 'exclude files' + for file_name in file_names: + dir_suffix = CONFIG['ci']['pyinstaller']['dir_suffix'][CONFIG.os] + content_suffix = CONFIG['ci']['pyinstaller']['content_suffix'][CONFIG.os] + freezed_app_path = os.path.join(CONFIG.dist_dir, f'{CONFIG.app_name}{dir_suffix}', f'{content_suffix}') + file_path = os.path.join(freezed_app_path, file_name) + for file_path in glob.glob(file_path): # for cases with '*' in the lib name + Functions.removeFile(file_path) + except Exception as exception: + Functions.printFailMessage(message, exception) + sys.exit(1) + else: + Functions.printSuccessMessage(message) + def runPyInstaller(): try: message = 'freeze app' @@ -139,27 +149,7 @@ def runPyInstaller(): sys.exit(1) else: Functions.printSuccessMessage(message) - -def excludeFiles(): - file_names = CONFIG['ci']['pyinstaller']['manual_exclude'] - if len(file_names) == 0: - Functions.printNeutralMessage(f'No libraries to be excluded for {CONFIG.os}') - return - try: - message = 'exclude files' - for file_name in file_names: - dir_suffix = CONFIG['ci']['pyinstaller']['dir_suffix'][CONFIG.os] - content_suffix = CONFIG['ci']['pyinstaller']['content_suffix'][CONFIG.os] - freezed_app_path = os.path.join(CONFIG.dist_dir, f'{CONFIG.app_name}{dir_suffix}', f'{content_suffix}') - file_path = os.path.join(freezed_app_path, file_name) - for file_path in glob.glob(file_path): # for cases with '*' in the lib name - Functions.removeFile(file_path) - except Exception as exception: - Functions.printFailMessage(message, exception) - sys.exit(1) - else: - Functions.printSuccessMessage(message) - + if __name__ == "__main__": copyMissingLibs() copyMissingPlugins() From c0571e1c7cc8a473f0756a2b6df9036996190c54 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Tue, 23 Nov 2021 21:53:20 +0100 Subject: [PATCH 10/10] Update RELEASE.md --- RELEASE.md | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index df5afc59..416fdb99 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,17 +1,3 @@ -### Features - -- Simulating and fitting time-of-flight (TOF) data using the [CrysPy](https://github.com/ikibalin/cryspy) calculation engine is now supported. -- Dependent and independent parameter constraints can be constructed for use during fitting. - ### Changes -- Reset the estimated standard deviations on the `Analysis` page after fitting if the `Fit` box becomes unchecked. - -### Bug Fixes - -- The [lmfit](https://lmfit.github.io/lmfit-py/) minimization engine now works with the [CrysFML](https://code.ill.fr/scientific-software/crysfml) and [GSAS-II](https://subversion.xray.aps.anl.gov/trac/pyGSAS) calculators. -- Now project reset clears the simulated curve, experimental data, background and constraints tables. -- Size of the simulation/analysis chart on the `Summary` page has been fixed. -- The `Project save` button enable/disable state is now properly defined. -- Fixed updating a sample model via the build-in `CIF editor`. -- Now undo/redo triggers a parameter table update on the `Analysis` page. +- The Python-based backend framework has been updated from version 3.7 to 3.8.