Skip to content

Add preferences dialog #2899

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

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

Conversation

k-dominik
Copy link
Contributor

@k-dominik k-dominik commented Aug 21, 2024

This PR makes the settings, so far governed only by ilastik.ini, accessible to users via the UI:

ilastik preferences dialog

In the process I introduced a config class based on pydantic. The settings, edited via the dialog, will be written to ilastik.ini - this is fully compatible with the settings file so far. Note: Only settings different to default values are written to the file.

Currently a full config would look like this:

Example ilastik.ini
[ilastik]
plugin_directories = ~/my_plugins
output_filename_format = {dataset_dir}/{nickname}_output_{result_type}
output_format = tiff
logging_config = /path/to/some/logging_config.json
debug = True
hbp = True

[lazyflow]
threads = 50
total_ram_mb = 10000

Todos:

  • reading/writing of config
  • user-friendly tooltips/validation
  • investigate pydantic (pydantic-settings, maybe) 🤡
    in the end pydantic-settings wasn't worth it - we don't want most of it's features (no need for .env files, we don't want to expose every setting via env variables, and also not via argparse (let alone that all of these would need to be customized to integrate with our current "interface")

Checklist

Fixes #2863

Copy link

codecov bot commented Aug 21, 2024

Codecov Report

Attention: Patch coverage is 69.54733% with 74 lines in your changes missing coverage. Please review.

Project coverage is 56.56%. Comparing base (cca71b7) to head (39eaca2).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...tik/applets/tracking/annotations/annotationsGui.py 0.00% 10 Missing ⚠️
ilastik/shell/gui/preferencesDialog.py 93.89% 6 Missing and 2 partials ⚠️
...astik/applets/tracking/manual/manualTrackingGui.py 0.00% 7 Missing ⚠️
ilastik/app.py 25.00% 2 Missing and 4 partials ⚠️
ilastik/config.py 84.61% 5 Missing and 1 partial ⚠️
ilastik/shell/gui/ilastikShell.py 40.00% 2 Missing and 4 partials ⚠️
ilastik/widgets/stackFileSelectionWidget.py 0.00% 3 Missing ⚠️
ilastik/workflows/__init__.py 0.00% 0 Missing and 3 partials ⚠️
ilastik/applets/edgeTraining/edgeTrainingGui.py 0.00% 0 Missing and 2 partials ⚠️
...ik/applets/objectExtraction/objectExtractionGui.py 0.00% 1 Missing and 1 partial ⚠️
... and 16 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2899      +/-   ##
==========================================
+ Coverage   56.45%   56.56%   +0.10%     
==========================================
  Files         535      536       +1     
  Lines       62264    62420     +156     
  Branches     7711     7729      +18     
==========================================
+ Hits        35154    35309     +155     
- Misses      25345    25348       +3     
+ Partials     1765     1763       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@k-dominik k-dominik force-pushed the settings-dlg branch 9 times, most recently from 563948b to 548c6b9 Compare August 28, 2024 06:25
@k-dominik k-dominik marked this pull request as ready for review August 28, 2024 07:03
Copy link
Contributor

@btbest btbest left a comment

Choose a reason for hiding this comment

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

Edit: This was meant to be "Request changes" because preferencesDialog.py has a bug in an else-raise-clause due to variable naming, default_config should be deleted (I think) and the flat_dict should be explained or removed.

Really nice, the widget generator and the prefs based on pydantic will make it pretty easy to extend the configurable options in the future.

I see a potential for confusion because we have a preferences.json, which the user can locate with Open Config Folder - but these are the volumina preferences. Now we have a Preferences dialog that controls a different set of preferences that we internally call config.

From the dev perspective, it might be worth just adding a short note to the respective docstrings to explain that ilastik-config goes with PreferencesDialog and that these are separate from preferences, which is from volumina. Though the code is easy enough to trace anyway.

From the user perspective, I'm not really sure what can be done. Maybe creating the ilastik.ini file with the default values could help, so that at least if a user uses Open Config Folder, they can see that there are in fact two separate sets of settings?

k-dominik and others added 4 commits December 2, 2024 17:18
* removed flattening of config dict - just works without
* removed `default_config` (not used) -> moved information docstring as example
* removed qtbot fixture from test that don't need it
* renamed `Increment.increment` member to `inc` to avoid confusion

Co-authored-by: Benedikt Best <[email protected]>
Some options are not validated very well. For now we hide those to
prevent changing them without much consideration.
Copy link
Contributor

@btbest btbest left a comment

Choose a reason for hiding this comment

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

:/

I realised there's an issue with coupling the dialog's model directly to the in-use runtime config: Regardless of whether you Ok or Cancel the dialog (which governs whether you write to disk), any non-default values you entered in the inputs are kept in the active runtime config. Also, if a non-default value was read from file, then resetting it to default in the dialog and clicking Ok doesn't actually transfer the value to the model.

The dialog does tell the user to please restart ilastik, but that should only be a precaution and not a requirement in order for Ok and Cancel to modify (or not modify) the ongoing runtime configs...

Request changes because there's also a remaining usage of the old config dict syntax in dataExportGui: settingsDlg = DataExportOptionsDlg(self, opExportModelOp, cfg["ilastik"]["output_filename_format"])

return widget, advanced

def initUI(self):
self._main_layout = QVBoxLayout()
Copy link
Contributor

@btbest btbest Dec 3, 2024

Choose a reason for hiding this comment

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

Now that I look at it again, I think all the layouts and widgets instantiated here can be local variables instead of self. properties, as they're not referenced in any other method or outside the class 😅

Comment on lines +188 to +189
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.resetButton = QPushButton("Reset to Defaults")
Copy link
Contributor

Choose a reason for hiding this comment

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

As far as I can see, buttonBox and resetButton aren't referenced outside the class, so prefix _? (Or as suggested in the other comment, make them all local variables only?)

Comment on lines +181 to +184
# adv_chbox_layout = QHBoxLayout()
self._adv_checkbox = QCheckBox("Show advanced options")
self._adv_checkbox.setTristate(False)
self._adv_checkbox.stateChanged.connect(lambda x: self._update_advanced_view(x != 2))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# adv_chbox_layout = QHBoxLayout()
self._adv_checkbox = QCheckBox("Show advanced options")
self._adv_checkbox.setTristate(False)
self._adv_checkbox.stateChanged.connect(lambda x: self._update_advanced_view(x != 2))
self._adv_checkbox = QCheckBox("Show advanced options")
self._adv_checkbox.setTristate(False)
self._adv_checkbox.stateChanged.connect(lambda state: self._update_advanced_view(state != Qt.Checked))

Comment on lines +89 to +91
pref_dict = self.config.model_dump(exclude_defaults=True)
cf = configparser.ConfigParser()
cf.read_dict(pref_dict)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
pref_dict = self.config.model_dump(exclude_defaults=True)
cf = configparser.ConfigParser()
cf.read_dict(pref_dict)
unvalidated = self.config.model_dump(exclude_defaults=True)
self.config = self.config.model_validate(unvalidated)
validated = self.config.model_dump(exclude_defaults=True)
cf = configparser.ConfigParser()
cf.read_dict(validated)

So that the stripped results are saved to file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Increase LAZYFLOW_THREADS max
2 participants