Skip to content

Unify icon contributions and clarify supported formats#450

Merged
Czaki merged 25 commits into
napari:mainfrom
brisvag:fix/icon-contributions
Jun 15, 2026
Merged

Unify icon contributions and clarify supported formats#450
Czaki merged 25 commits into
napari:mainfrom
brisvag:fix/icon-contributions

Conversation

@brisvag

@brisvag brisvag commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

This PR aims to unify a bit the manifest regarding icons, and to bring it more in line with what the underlying app-model accepts.

We actually "officially" support more things than appmodel (e.g: https urls), and I'm not sure whether we plan to keep these and handle the extra logic ourselves or what else to do. At least with this we start supporting dark/light for all icon fields.

@willingc willingc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good. Seems to have a circular import that in the tests.

Comment thread src/npe2/manifest/_validators.py Outdated
@brisvag

brisvag commented Apr 13, 2026

Copy link
Copy Markdown
Contributor Author

Since it's not reused, I just moved the validator to the model where it's needed.

@codecov

codecov Bot commented Apr 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (fc22c92) to head (9db3f7a).

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #450   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           37        37           
  Lines         2795      2802    +7     
=========================================
+ Hits          2795      2802    +7     

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/npe2/manifest/schema.py Outdated
Comment thread src/npe2/manifest/contributions/_commands.py Outdated
Comment thread src/npe2/manifest/contributions/_submenu.py Outdated
@brisvag brisvag added the enhancement New feature or request label May 13, 2026
Comment thread tests/test_manifest.py Outdated
PluginManifest(name="myplugin", icon="my_plugin:myicon.png")
pm = PluginManifest(name="myplugin", icon="my_plugin:myicon.png")
assert pm.icon == "my_plugin:myicon.png"
pm = PluginManifest(name="myplugin", icon="https://example.com/icon.png")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think that we should allow remote icons in plugins. This is a big privacy issue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Actually, this is a really important point, it let's someone track things, like the 1px by 1px white image in your emails.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok, I agree. I was just trying to keep previous "behaviour" :)

@brisvag

brisvag commented May 14, 2026

Copy link
Copy Markdown
Contributor Author

Ok, urls no longer accepted.

@TimMonko TimMonko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Implementation looks good to me
Can we get some documentation in napari/docs about the "ship with sdist" bit. I think src/plugin/some_module/icon.svg is not by default included in the sdist because it is not a .py

This will result in plugin developers locally seeing everything as ok (because their -e install contains it) but then the wheel installed version would be wrong.

But also, maybe we shouldn't reference sdist here? Wheels are always built with the sdist (AFAIK), but that's still managed via pyproject.toml not MANIFEST.in. So maybe we just link to a good packaging resource that talks about how to include files that are not .py files in builds Ok now I'm a bit confused, has this changed? In ndevio I have .tiff and .png's as sample data but looking closely I did absolutely nothing to include them in the wheel... hmmm, no MANIFEST and nothing in pyproject
Have things changed?

@Czaki

Czaki commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Ok now I'm a bit confused, has this changed? In ndevio I have .tiff and .png's as sample data but looking closely I did absolutely nothing to include them in the wheel... hmmm, no MANIFEST and nothing in pyproject

It is because you use hatchling as build backend, and this that you described is connected with setuptools backend. Hatchling includes all data from repository by default.

@TimMonko TimMonko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Was about to merge and wanted to double check the logic because I was trying to update the PR description properly. Looks like maybe we dropped fonticon compatibility? And, I guess I'm not seeing where we block urls now?
I could just be having a brain fart...

Comment thread src/npe2/manifest/_validators.py Outdated
assert isinstance(v, str), f"{v} must be a string"
return v
def _ensure_valid_resource(value):
if ":" not in value:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

does this change not invalidate using the fonticon key method? AFAICT, this makes it so only package resources would not raise the value error.

Comment thread tests/test_manifest.py
@brisvag

brisvag commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

Mmm you're right... The problem is that validating the manifest should not necessarily require that the resources are present or the fonticon plugin is isntalled, so it's hard to properly check this... I guess we can check that a . is in the text in the same way, but at this point I wonder if checking anything makes sense here...

@TimMonko

Copy link
Copy Markdown
Contributor

I think it makes sense to validate still, especially to intentionally block urls.
Maybe just do urllib.parse since its a python builtin? Then yeah, for the resource check just look for .
Although, is there any instance where a uri would work in general? Could just check for //? It's not possible for a package resource or fonticon key to have that

@brisvag

brisvag commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

So, good news is I updated the validator and now it should handle all the cases... bad news is: we actually have url icons in tests, which made me realize: this is a breaking change in theory... do we need to migrate? Do we need to check if plugins in the wild are setting the icon?

@TimMonko

Copy link
Copy Markdown
Contributor

Do we need to check if plugins in the wild are setting the icon?

I will check manifests in npe2api. If you don't hear from me by the time you wake up tomorrow send me a DM

TimMonko and others added 3 commits May 28, 2026 13:36
@TimMonko

Copy link
Copy Markdown
Contributor

Ok, so I fixed the tests (the sample napari.yaml was still using a url) and I added some more things to test_icon because I was curious about submodules and the commands/submenus.

Checking on the icon usage in npe2api now

@TimMonko

TimMonko commented May 28, 2026

Copy link
Copy Markdown
Contributor

Not a single plugin scraped by npe2api declares an icon except napari-trackastra, and it uses "icon": "resources/icon.png",
I used the regex: "icon"\s*:\s*"(?!")([^"]+) to find anything that was "icon": "*" and it would skip any that are null (no quote) and "" (quote follows quote) which are the default entries.

There are five other instances that meet this regex, but all are colors used for the three theme plugins that exist: napari-gruvbox, napari-solarized, ndev-themes

So as long as our conda-only plugins don't do this we are good to go. But the conda-only plugin authors seem to be quote responsive these days.

@TimMonko TimMonko added the ready to merge Last chance for comments! Will be merged in ~24h label May 28, 2026
@brisvag

brisvag commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

resources/icon.png

Hold on, this won't work now! It needs to be some.module.resources:icon.png

Maybe we can contact them and open a PR.

@Czaki

Czaki commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

What is currrent status. Three plugins that are listed by @TimMonko are @brisvag, @aganders3 and @TimMonko plugin?

Could we merge this PR and make release, or should we wait?

@TimMonko

TimMonko commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

What is currrent status. Three plugins that are listed by @TimMonko are @brisvag, @aganders3 and @TimMonko plugin?

Could we merge this PR and make release, or should we wait?

The only one of concern is napari-trackastra `"icon": "resources/icon.png", as @brisvag says #450 (comment)

The theme plugins are unaffected by this, I was mostly just showing that I did do diligence to look for "icon" (which themes change but are unaffected by this issue)

I think our best way forward is contact napari-trackastra and merge this PR

@brisvag

brisvag commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

I'll do the contacting, feel free to merge!

@Czaki Czaki merged commit e2b0dd6 into napari:main Jun 15, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request ready to merge Last chance for comments! Will be merged in ~24h

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants