Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
16 changes: 1 addition & 15 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -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.
30 changes: 15 additions & 15 deletions easyDiffractionApp/Gui/Components/UserTutorialsController.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -266,7 +266,7 @@ EaElements.RemoteController {
rc.mouseClick(ExGlobals.Variables.zProjectionButton)
rc.mouseClick(ExGlobals.Variables.defaultViewButton)

rc.wait(1000)
rc.wait(5000)

// Experiment Tab

Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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)

Expand All @@ -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)

Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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' }
Expand All @@ -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' # 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' }
Expand Down Expand Up @@ -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'] }
Expand Down
80 changes: 45 additions & 35 deletions tools/Scripts/FreezeApp.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import os, sys
import glob
import site
import PySide2, shiboken2
import cryspy, GSASII
import easyCore, easyDiffractionLib, easyApp
Expand All @@ -16,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]
Expand All @@ -29,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': '.'},
Expand All @@ -38,24 +47,25 @@ 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': '.'})

# 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]
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})
# 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 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 copyMissingLibs():
missing_files = CONFIG['ci']['pyinstaller']['missing_pyside2_files'][CONFIG.os]
if len(missing_files) == 0:
Expand Down Expand Up @@ -95,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'
Expand All @@ -119,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()
Expand Down
2 changes: 1 addition & 1 deletion tools/Scripts/Functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down