Hi all, working my way through the current plugin (dependency) installer mechanism, I have a few questions.
Bottom line: What kind of assumptions can a plugin safely make about its dependencies and their initialization (from QGIS' perspective)? Imagine two plugins: "PluginA" and "PluginB". PluginA depends on PluginB, i.e. if a user was installing PluginA, current QGIS would ask him to install PluginB as well. Now the plugin system in QGIS does three things actually: - Installing and uninstalling plugins - Loading (i.e. importing, in Python terms) and unloading plugins - Starting and stopping (`initGui` + friends and `unload`) In comparison, typical package managers usually do not care about the loading and starting part. This is because usually a package installer does run outside of the scope of the stuff that is using the packages. So if a user was installing PluginA in QGIS, the following sequence would be triggered: - Install PluginA - Find dependencies of PluginA: PluginB - Install PluginB - Load PluginB - Start PluginB - Load PluginA - Start PluginA PluginB would be loaded (imported) and started before PluginA. Depending on the use-case, this can make a lot of sense. Unfortunately, if a user was restarting QGIS, the loading and starting sequence would depend on (as it appears) the order of plugin folders on the filesystem which can be more or less "random". So here, PluginA can not rely on PluginB to have been loaded and/or started in advance at the moment. This leads to many potential problems, some of which were discussed here (Nyall's comment being the most interesting one for me): https://github.com/qgis/QGIS-Enhancement-Proposals/issues/132#issuecomment-460136324 So the question now is: How is PluginA supposed to interact with PluginB? Thanks to the way `sys.path` is configured in QGIS, PluginA could easily run `import PluginB` and it would actually work. QGIS has a modified `builtins.__import__` method which would even track this import. This would sort of allow to treat PluginB as a "normal" Python package and be equivalent to `qgis.utils.loadPlugin("PliginB")`, for better or for worse. A possible alternative is that PluginA requires PluginB to initialize itself through `classFactory` (or `serverClassFactory`). PluginA's best (and probably safest) option then would be to run `qgis.utils.startPlugin("PluginB")` (or `startProcessingPlugin` / `startServerPlugin`). PluginA could now basically access the instance of PluginB's class through `qgis.utils.plugins["PluginB"]` (or `server_plugins`). All of the above is fragile in many ways and - as far as I can tell - more or less undocumented. How much of the described API in `qgis.utils` is supposed to be available to "the public", i.e. to plugins? As far as I can see, only one plugin (for QGIS 3.8 or later) in the plugin repository actually uses inter-plugin dependencies (properly), so there are not many examples of how things should look like. QEP 132 also is not really detailed about the exact behavior and assumptions a plugin's author can make. Fortunately, the current lack of "downstream" users and the lack of "established" documentation opens the option to "fix" the system without breaking too much stuff if desired. Final questions: - How is the *current* plugin-dependency system supposed to be used / not supposed to be used from your perspective? - How do you envision an actual plugin-dependency system to work (with respect to interactions between plugins)? - Does it make sense to care about plugin dependencies when QGIS is loading and starting plugins (so dependencies are loaded & started first)? Best regards, Sebastian _______________________________________________ QGIS-Developer mailing list QGIS-Developer@lists.osgeo.org List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer