napari
napari copied to clipboard
Define allowed plugin contribution
Currently, the list of menu contribution points are not defined, and we need to
- figure out the strategy of whether we want to start with more constraint or less constraint (black list vs. white list)
- define the rules of the contribution point
more context https://github.com/napari/npe2/pull/161/files
current code: https://github.com/napari/napari/blob/e6c5576817c62c7900b27c577070d9e810b24758/napari/_app_model/constants/_menus.py#L38-L40
the output should be a miniNap or NAP documenting all the contribution points if cannot get consensus in quick discussions
@haesleinhuepf any thoughts on this?
Great that you bring this up @potating-potato ! I'm pretty sure this was discussed earlier, but I can't find the GitHub issue right now. My proposal would be (inspired by the SciJava plugin mechanism:
- Set up a plugin-service pattern in napari. That is a generic approach: everything can plug into any kind of service. Services can provide all plugins that registered in the service. This approach makes napari super open to be extended by the community. Once this is achieved you can:
- Setup default services in napari: ImageProcessing-Service, Menu-Service, Viewer-Service, etc. People can then program plugins that do image processing, show up in the menu or can view something. Once this is achieved you can:
- Show the community how to use the pattern within their plugins by programming their own services. This enables plugins plugging into plugins. Trackmate is the most amazingly extensible plugin that shows the capabilities of this approach.
From my perspective the experts on these kind of things are @ctrueden @tinevez @royerloic @gselzer. Maybe they can give additional hints and suggestions.
In general that makes sense! we currently have a similar pattern in place, not exactly service driven but achieves similar goals, using napari-demo as an example:
https://github.com/chanzuckerberg/napari-demo/blob/0e651e5512a7367d364fe241c076c11d73009136/napari_demo/napari.yaml#L61-L66
menus: napari/layers/context: # FIXME move this somewhere else after more menu contribution is defined - submenu: hello_world - command: napari-demo.about hello_world: - command: napari-demo.hello_world
the demo plugin declares a menu under the napari/layers/context, which would look like this:

we should define the list of places where we want the plugins to contribute such menus, in addition to napari/layers/context. I wonder if we would then open up possibilities to register under all existing menus, which are "File", "View", "Window", "Plugins", "Help". If we want to be conservative we could restrain the contribution to "Plugins" only?
Wow, cool! I'm curious: How could I ask napari for all plugins of kind "View"?
I don't think it can be searched yet. also we may not want to categorize plugins based on their menu contribution. also just to make sure, by "File", "View", "Window", "Plugins", "Help", I meant this:
Yes, agreed, I would also not categorize things according to its menu. Again, I would design it as open as possible. Anything should be able to plug into anything. If you can the search for plugins that can do "X" it becomes really powerful. Imagine the right click menu on layers searches for plugins that can do "projections" and lists them in a sub-menu. Or the File > Save menu searches for plugins that can do "write to disc" and lists them in a sub menu. Or the "Preprocessing" plugin searches for plugins that can do "denoise" and lists them in a pulldown. Or... 😉
some of the trade-off here would be future-proof and deprecations. If we take a complete open approach, then there is an extra burden if we later decide not to allow plugins to insert into certain places. It also makes deprecation and version management harder, especially on renamings of top-level menus, etc.
if we later decide not to allow plugins to insert into certain places
The past has shown, whenever core developers prevent others to extend certain things , others will break the barriers and do it anyway in terrible ways.
Again, I recommend opening napari for extensions - in very very general.
Any @napari/core-devs want to provide opinions here in terms of where plugins should be allowed to insert menus? If everyone is on board with starting broadly and allow plugins to register everywhere, maybe except a few defined places using a blacklist approach (compared to the current prototype using a white list approach defining places where plugins are allowed to insert menus), I can create a PR to update the constraint
In general, I do not have a problem with contributions anywhere. It will be nice to have the option to determine from which plugin the contribution comes (for example, for each plugin GUI with information about all contributions), and in the future granular option to disable/enable such contributions. Without this, it may end with too many items in menus if someone has more than a few plugins.
No specific preference on constraints, but it would be nice to have some way to know which menu items are built-ins versus the ones from plugins, and know which plugin contributes to a specific menu item.
Rationale: Users may try to follow a napari video tutorial and find the menu items different from their napari. Without the differentiation, it's hard to know if the difference is due to missing a plugin or different napari versions that may come with different menu items.
I don't mind if the allowed list is quite large but I think the default policy should be that we have to explicitly whitelist places plugins are allowed to contribute, not give total free reign
I agree, we should at a minimum give directions/indications on where plugins are supposed to attach. A little icon/symbol on the menu item shownign that it's a plug in contribution would be cool as well (would be awesome in the future if plugin developers could even provide their own con for this!).
I think for now the best approach would be to open up a few obvious places, and encourage people to suggest adding to the whitelist in core napari, rather than doing weird workarounds. As long as we whitelist most reasonable places, I expect most developers will take an error as an indication that there's a better spot rather than a straight up no. We really don't want the menu to become a total un-navigable mess.
No specific preference on constraints, but it would be nice to have some way to know which menu items are built-ins versus the ones from plugins, and know which plugin contributes to a specific menu item.
Rationale: Users may try to follow a napari video tutorial and find the menu items different from their napari. Without the differentiation, it's hard to know if the difference is due to missing a plugin or different napari versions that may come with different menu items.
In Fiji you can look up what jar/plugin provides a SciJava command. This is a useful feature for both users and devs (especially for getting feedback on bug reports). This is a great suggestion @chili-chiu
@psobolewskiPhD introduces 3 issues (#5080, #5091, #5092) that make this issue much more complex if solved, as requires implementing the strategy of declaring contribution per system and a way to solve it if someone does not have access to all system or does not know conventions.
@Czaki If I read those macOS usability issues correctly, the suggested solution is simply to change napari—in general, for all OSes—to the correct order established by Apple and very often mimicked on Windows and Linux. So: reorder the menus to the standard order, put standard commands where they are normally found in other apps (e.g. window manipulation in Window, not View), fix the maximize label and shortcut, etc. I agree with @psobolewskiPhD that it's not necessary to customize it per OS (at least: not heavily—ImageJ/Fiji makes some small adjustments per OS, but nothing that complexifies the creation of extensions).
As for contributions violating those standards: in my experience with ImageJ/Fiji, most developers try to abide by them, and the more consistent the structure and rules, the easier it is for devs to see what they should be doing. Yes, sometimes standards are violated, and you end up with e.g. a new top-level menu. But users can file issues on a per-extension basis for those things to be fixed. I would vote for an 80/20 solution here: enforce what's easy to enforce, but don't spend too much time inventing complex subsystems just to stop people from doing things that would later be caught and fixed anyway by PR review and/or user feedback.
From today's community meeting (my remarks): It would be nice if the plugin could contribute a dynamic submenu generated by a function called on menu creation. This may allow for the support of multiple scenarios that, in another case may require creating separate actions.
Sample scenarios for right-click context menu:
- split layer along the given axis. Could be simulated using conditions (show menu entry if the layer has more than five axes etc), but if data will have more layers than predicted, then it will not work
- Enable-disable given class of objects in points/vectors/shapes/labels Layer base on properties.
The downside of such a method may be the performance of such functions, but it may be achieved by some caching output of such functions and refreshing the cache base on events.
EDIT. Also, @haesleinhuepf plugins that parse environment and create entries based on this environment may benefit from this, as such calculation may be done after open napari window.
From today's community meeting (my remarks): It would be nice if the plugin could contribute a dynamic submenu generated by a function called on menu creation. This may allow for the support of multiple scenarios that, in another case may require creating separate actions.
Sample scenarios for right-click context menu:
- split layer along the given axis. Could be simulated using conditions (show menu entry if the layer has more than five axes etc), but if data will have more layers than predicted, then it will not work
- Enable-disable given class of objects in points/vectors/shapes/labels Layer base on properties.
The downside of such a method may be the performance of such functions, but it may be achieved by some caching output of such functions and refreshing the cache base on events.
EDIT. Also, @haesleinhuepf plugins that parse environment and create entries based on this environment may benefit from this, as such calculation may be done after open napari window.
fwiw, there is some limited feature that can help in this case, a condition can be declared on the plugin menu, and this condition is later evaluated by the context manager to decide whether a menu is shown: https://github.com/napari/npe2/blob/596d750deb478605eb47ae5989a541a2fcfb30eb/npe2/manifest/contributions/_menus.py#L12-L17
I mention this mechanism in my comment. But it is really limited.
Quick summary:
Allowed contribution points Some support for anywhere (https://github.com/napari/napari/issues/5079#issuecomment-1247124790, https://github.com/napari/napari/issues/5079#issuecomment-1248753761). Problems raised with future-proof and deprecations (https://github.com/napari/napari/issues/5079#issuecomment-1247120223). Proposal for 'plugin-service' pattern where services provide all plugins that registered in the service e.g., the File > Save menu searches for plugins that can do "write to disc" and lists them in a sub menu (https://github.com/napari/napari/issues/5079#issuecomment-1246954425)
More support for having a white list (https://github.com/napari/napari/issues/5079#issuecomment-1248918152, https://github.com/napari/napari/issues/5079#issuecomment-1249250091)
Related issues
Support for menu items to indicate that they are from a plugin and also potentially which plugin they come from (https://github.com/napari/napari/issues/5079#issuecomment-1248753761, https://github.com/napari/napari/issues/5079#issuecomment-1248762393, https://github.com/napari/napari/issues/5079#issuecomment-1249250091, https://github.com/napari/napari/issues/5079#issuecomment-1249285710)
Mention of issues (https://github.com/napari/napari/issues/5080, https://github.com/napari/napari/issues/5091, https://github.com/napari/napari/issues/5092) which propose to change napari to mirror Apple menu order and command layout.
Suggestion of dynamic sub-menu generation (https://github.com/napari/napari/issues/5079#issuecomment-1253525051)
It might be useful to decide which of these related issues we wish to implement and if defining allowed plugin contribution requires the related issue to be solved as well.
Porting over the whitelist we will be starting with from the discussion on NPE2 side:
Menu("/napari/layer_context", "Process Layer"),
Menu("/napari/layer_context/projections", "Make Projection"),
Menu("/napari/layer_context/convert_type", "Convert datatype"),
Menu("/napari/tools/acquisition", "Acquisition"),
Menu("/napari/tools/classification", "Classification"),
Menu("/napari/tools/filters", "Filters"),
Menu("/napari/tools/measurement", "Measurement"),
Menu("/napari/tools/segmentation", "Segmentation"),
Menu("/napari/tools/projection", "Projection"),
Menu("/napari/tools/transform", "Transform"),
Menu("/napari/tools/utilities", "Utilities"),
Menu("/napari/tools/visualization", "Visualization"),