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

Don't autocreate user dirs immediately when importing classes.info #4553

Merged
merged 9 commits into from
Dec 9, 2021

Conversation

ferdnyc
Copy link
Contributor

@ferdnyc ferdnyc commented Nov 25, 2021

Our PPA builds for 2.6.1 are currently broken in Launchpad, because I turned on documentation building which immediately crashed. The problem is that the Sphinx config does an import of classes.info to get the OpenShot version, and as soon as it's imported classes.info attempts to create all of the preferences directories in $HOME/.openshot_qt, a no-no during package builds.

I assume this is also why the unit tests are disabled, in the launchpad configs.

All of this makes the point, though, that we SHOULDN'T BE creating a ton of directories simply because a class was imported — especially not one we import everywhere, from setup.py to doc/conf.py to freeze.py to src/tests/query_tests.py. That's an unacceptable side-effect for a class that's intended as merely a metadata dumping ground.

So, these commits move the creation of directories into a function within classes.info, setup_userdirs(), which launch.py calls immediately prior to setting up the OpenShotApp instance. All of the other scripts that import the class won't call it, so they don't trigger the creation of a bunch of unnecessary settings dirs as a side-effect.

To make this work, I had to rearrange a bunch of things in classes.settings, classes.logger, classes.project, and classes.app so that they could handle the user preferences dir being entirely absent, since the unit tests need to be able to import classes.app and create an OpenShotApp instance without ever calling classes.info.setup_userdirs().

I also removed the load of classes.logger from classes.sentry — if that's going to be loaded at the very start of the launch script, it can't trigger the initialization of the logging class. It's too early. So it just does a print() of the info instead, same as how launch.py handles its own output.

And I removed all references to the mode from the GUI code, as the unit tests haven't started the GUI for some time now. window.mode will never be "unittest" under any circumstances, anymore. (app.mode is still used by the unit tests to adjust certain startup functionality, so it's still there. Also it's now set as an instance variable, so if any of the code ever does need to check the mode, it can test if get_app().mode == "unittest".)

With these changes, it's now possible to do all of these things:

  • Build, install, or package the application
  • Build the user manual
  • Run the unit tests

...WITHOUT triggering the creation of $HOME/.openshot_qt/ and its many, many subdirs.

Unfortunately I wasn't able to arrange things so that OpenShot itself could run entirely without a user dir as a 0-footprint application. That's something I see value in (temporary files would just be written to system default tempdirs, is the idea) since it would allow use of OpenShot in all sorts of scenarios where writing to $HOME/.openshot_qt is not feasible, permitted, or desired. But, it's a bigger undertaking that shouldn't hold up these changes.

Update

I added a few more commits:

  1. classes.info now captures all of the initial defaults for user paths. (Any variable with a name that ends with _PATH, and a value that matches info.USER_PATH at the start is placed into the info._path_defaults dict.)

    • That captured dict is now used in info.setup_userdirs() (replacing the hardcoded list of variables representing paths to be created)
    • The defaults can be reapplied to reset any modified info paths, by calling info.reset_paths().
    • The default value for a path can be retrieved even if the current value has been modified, by calling info.get_default_path("NAME_OF_VAR").
    • Most (hopefully all, but I can't promise that) of the rest of the code that was responsible for resetting info paths now does so by simply calling info.reset_paths().
    • Code that had to ad-hoc things like os.path.join(info.USER_PATH, "thumbnails") to work around a modified info.THUMBNAIL_PATH now instead just calls info.get_default_path("THUMBNAIL_PATH").
  2. I re-worked the autosave code a bit. The project.save() method, which used to have two parameters make_paths_relative and move_temp_files, now has only one: backup_only. Setting backup_only=True implies both of the previous parameters False, and also disables some additional logic that's undesirable when making a backup. (Like the storing of current_filepath and the resetting of has_unsaved_changes, both of which were previously being done in project.save(), then immediately un-done by the autosave code that called it. Now it's never done in the first place, because backup_only=True is passed in with the call.)

  3. I renamed MainWindow.clear_all_thumbnails() to MainWindow.clear_temporary_files(), because I just couldn't abide the previous name for a function that not only cleared three different types of working file, but also deleted the (previous) backup file! A name that bad was just asking for someone to make a wrong assumption, possibly with consequences.

@ferdnyc ferdnyc force-pushed the no-autocreate-dirs branch 2 times, most recently from 94f7380 to 2b75b88 Compare November 25, 2021 23:00
Copy link
Collaborator

@JacksonRG JacksonRG left a comment

Choose a reason for hiding this comment

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

LGTM

# Migrate USER_DEFAULT_PROJECT from former name
if all([
os.path.exists(LEGACY_DEFAULT_PROJECT),
not os.path.exists(USER_DEFAULT_PROJECT),
Copy link
Collaborator

Choose a reason for hiding this comment

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

neat way to make a very readable "and not"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Standard disclaimer about any() and all() not supporting short-circuit evaluation applies (all of the conditions in the list will always be evaluated, unlike in a multi-clause if .. and/or ... condition), but for simple, one-time tests like this one the efficiency loss is undetectable.

src/classes/info.py Outdated Show resolved Hide resolved
@github-actions
Copy link

github-actions bot commented Dec 9, 2021

Merge conflicts have been detected on this PR, please resolve.

@github-actions github-actions bot added the conflicts A PR with unresolved merge conflicts label Dec 9, 2021
@ferdnyc
Copy link
Contributor Author

ferdnyc commented Dec 9, 2021

Merging this, as it should restore our Launchpad builds to working order.

ferdnyc and others added 9 commits December 9, 2021 17:00
- The directory-creation code is moved to info.setup_userdirs(),
  called by launch.py before creating the OpenShotApp instance
- app.mode is now set by keyword-only argument, and is no longer
  passed to MainWindow() (as the GUI is never started in unit test
  mode).
- Removed all references to window.mode from the GUI code
- The directory-creation code is moved to info.setup_userdirs(),
  called by launch.py before creating the OpenShotApp instance
- app.mode is now set by keyword-only argument, and is no longer
  passed to MainWindow() (as the GUI is never started in unit test
  mode).
- Removed all references to window.mode from the GUI code

Co-authored-by: Jackson <jackson@openshot.org>
If the info.USER_PATH directory does not exist, load the settings
defaults, but don't try to merge the user's settings or to write
back the updated settings file immediately after loading.
- project.save(make_paths_relative=False, move_temp_files=False) both
  replaced with backup_only=True, which does the same plus adds
  additional protections against unwanted actions
- Backup-only save files will now retain absolute paths, as was
  apparently intended (make_paths_relative=False was being ignored)
- clear_all_thumbnails was an unmaintainable name for a function that
  not only deleted three different types of working files, but ALSO
  deleted the (previous) project data backup!
- Now uses info.get_default_path() to avoid hard-coding directory
  names under `info.USER_PATH`
@ferdnyc ferdnyc force-pushed the no-autocreate-dirs branch from af46db6 to 4f0b596 Compare December 9, 2021 22:03
@ferdnyc
Copy link
Contributor Author

ferdnyc commented Dec 9, 2021

(Just waitin' on the CI, to merge.)

@ferdnyc ferdnyc merged commit 8b3f9cd into OpenShot:develop Dec 9, 2021
@ferdnyc ferdnyc deleted the no-autocreate-dirs branch December 9, 2021 23:02
@ferdnyc
Copy link
Contributor Author

ferdnyc commented Dec 10, 2021

Success! And now there's an openshot-qt-doc package containing the user manual, as well.

@ferdnyc
Copy link
Contributor Author

ferdnyc commented Dec 10, 2021

Oops. But I have to fix Bionic, which doesn't have python3-sphinx-copybutton available. Fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
conflicts A PR with unresolved merge conflicts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants