[QGIS-Developer] Understanding inter-plugin dependencies and plugin loading - what can a plugin expect from a dependency?
Sebastian M. Ernst
ernst at pleiszenburg.de
Tue Apr 28 10:38:50 PDT 2020
Hi all,
sorry for my lengthy email last week - but this issue is still spinning
in my head and blocking progress in my test-bed plugin installer
re-implementation.
PR#9619 actually has two interesting comments ...
https://github.com/qgis/QGIS/pull/9619#issuecomment-476499538
https://github.com/qgis/QGIS/pull/9619#issuecomment-476550817
... in terms of use-cases for inter-plugin dependencies, their current
limitations and their (potential) correct use. The second comment is
interesting in terms of how one plugin should correctly expose a
"stable" API to other plugins: By injecting code into `qgis.plugins` *at
runtime* and exposing something like for instance
`qgis.plugins.QuickWkt`. The idea is interesting but it essentially
suffers from what I described: The absolutely non-deterministic loading
sequence. So it is not an actual, reliable solution at the moment -
unless the plugin requiring this API does some serious checking prior to
accessing its desired API and calls into the mostly undocumented API of
`qgis.utils` as a fallback solution.
How should a plugin author handle this at the moment (with QGIS 3.8 to
3.12)?
Best regards,
Sebastian
Am 23.04.20 um 20:46 schrieb Sebastian M. Ernst:
> 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 at lists.osgeo.org
> List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
> Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
>
More information about the QGIS-Developer
mailing list