Skip to content

Commit 40b67d7

Browse files
DragaDoncilaDraga Doncila
andauthored
Fix naming of npe1 converted contribution commands and add tests (#374)
Prior to this PR, declaring multiple implementations of the same hookspec in an npe1 plugin would lead to a converted manifest with multiple commands of the same ID e.g. `plugin_name.get_reader` multiple times, or `plugin_name.write_labels` multiple times. Even though this is technically "valid" per the schema, it should not be, because this leads to errors in trying to register the commands in napari. App-model (correctly, imo), does not allow you to register multiple commands with the same ID. We should update the schema validator to disallow multiple declarations of the same command ID, but in the meantime, this PR disambiguates converted commands for the same hook spec by using the function name instead of the spec name. --------- Co-authored-by: Draga Doncila <[email protected]>
1 parent c536e39 commit 40b67d7

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

src/npe2/_inspection/_from_npe1.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,11 +404,11 @@ def _parse_writer(self, impl: HookImplementation, layer: str):
404404
)
405405

406406
def add_command(self, impl: HookImplementation, py_name: str = "") -> str:
407-
name = impl.specname.replace("napari_", "")
408-
id = f"{self.package}.{name}"
409-
title = " ".join(name.split("_")).title()
410407
if not py_name:
411408
py_name = _python_name(impl.function)
409+
name = impl.function.__name__
410+
id = f"{self.package}.{name}"
411+
title = " ".join(name.split("_")).title()
412412
c = CommandContribution(id=id, python_name=py_name, title=title)
413413
self.contributions["commands"].append(c)
414414
return id

tests/npe1-plugin/npe1_module/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ def gen_data(): ...
1818
def napari_get_reader(path): ...
1919

2020

21+
@napari_hook_implementation(specname="napari_get_reader")
22+
def napari_other_reader(path): ...
23+
24+
2125
@napari_hook_implementation
2226
def napari_write_image(path, data, meta): ...
2327

@@ -26,6 +30,10 @@ def napari_write_image(path, data, meta): ...
2630
def napari_write_labels(path, data, meta): ...
2731

2832

33+
@napari_hook_implementation(specname="napari_write_labels")
34+
def napari_other_write_labels(path, data, meta): ...
35+
36+
2937
@napari_hook_implementation
3038
def napari_provide_sample_data():
3139
return {

tests/test_conversion.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,32 @@ def test_conversion_from_module(mock_npe1_pm, npe1_plugin_module):
2525
assert isinstance(mf.dict(), dict)
2626

2727

28+
@pytest.mark.filterwarnings("ignore:Failed to convert napari_provide_sample_data")
29+
@pytest.mark.filterwarnings("ignore:Error converting function")
30+
@pytest.mark.filterwarnings("ignore:Error converting dock widget")
31+
def test_conversion_multiple_readers(mock_npe1_pm, npe1_plugin_module):
32+
mf = manifest_from_npe1(module=npe1_plugin_module)
33+
assert isinstance(mf.dict(), dict)
34+
assert (readers := mf.contributions.readers) is not None
35+
reader_commands = {r.command for r in readers}
36+
assert len(reader_commands) == 2
37+
assert "dynamic.napari_get_reader" in reader_commands
38+
assert "dynamic.napari_other_reader" in reader_commands
39+
40+
41+
@pytest.mark.filterwarnings("ignore:Failed to convert napari_provide_sample_data")
42+
@pytest.mark.filterwarnings("ignore:Error converting function")
43+
@pytest.mark.filterwarnings("ignore:Error converting dock widget")
44+
def test_conversion_multiple_writers(mock_npe1_pm, npe1_plugin_module):
45+
mf = manifest_from_npe1(module=npe1_plugin_module)
46+
assert isinstance(mf.dict(), dict)
47+
assert (writers := mf.contributions.writers) is not None
48+
writer_commands = {r.command for r in writers}
49+
assert len(writer_commands) == 3
50+
assert "dynamic.napari_write_labels" in writer_commands
51+
assert "dynamic.napari_other_write_labels" in writer_commands
52+
53+
2854
def test_conversion_from_obj_with_locals(mock_npe1_pm):
2955
from napari_plugin_engine import napari_hook_implementation
3056

0 commit comments

Comments
 (0)