File: test_conversion.py

package info (click to toggle)
python-npe2 0.7.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 784 kB
  • sloc: python: 7,266; makefile: 19
file content (207 lines) | stat: -rw-r--r-- 7,511 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
from importlib.metadata import PackageNotFoundError

import pytest

from npe2._inspection import _from_npe1
from npe2._inspection._from_npe1 import (
    convert_repository,
    get_top_module_path,
    manifest_from_npe1,
)


@pytest.mark.filterwarnings("ignore:The distutils package is deprecated")
@pytest.mark.filterwarnings("ignore:Found a multi-layer writer in")
@pytest.mark.parametrize("package", ["svg"])
def test_conversion(package):
    assert manifest_from_npe1(package)


@pytest.mark.filterwarnings("ignore:Failed to convert napari_provide_sample_data")
@pytest.mark.filterwarnings("ignore:Error converting function")
@pytest.mark.filterwarnings("ignore:Error converting dock widget")
def test_conversion_from_module(mock_npe1_pm, npe1_plugin_module):
    mf = manifest_from_npe1(module=npe1_plugin_module)
    assert isinstance(mf.dict(), dict)


@pytest.mark.filterwarnings("ignore:Failed to convert napari_provide_sample_data")
@pytest.mark.filterwarnings("ignore:Error converting function")
@pytest.mark.filterwarnings("ignore:Error converting dock widget")
def test_conversion_multiple_readers(mock_npe1_pm, npe1_plugin_module):
    mf = manifest_from_npe1(module=npe1_plugin_module)
    assert isinstance(mf.dict(), dict)
    assert (readers := mf.contributions.readers) is not None
    reader_commands = {r.command for r in readers}
    assert len(reader_commands) == 2
    assert "dynamic.napari_get_reader" in reader_commands
    assert "dynamic.napari_other_reader" in reader_commands


@pytest.mark.filterwarnings("ignore:Failed to convert napari_provide_sample_data")
@pytest.mark.filterwarnings("ignore:Error converting function")
@pytest.mark.filterwarnings("ignore:Error converting dock widget")
def test_conversion_multiple_writers(mock_npe1_pm, npe1_plugin_module):
    mf = manifest_from_npe1(module=npe1_plugin_module)
    assert isinstance(mf.dict(), dict)
    assert (writers := mf.contributions.writers) is not None
    writer_commands = {r.command for r in writers}
    assert len(writer_commands) == 3
    assert "dynamic.napari_write_labels" in writer_commands
    assert "dynamic.napari_other_write_labels" in writer_commands


def test_conversion_from_obj_with_locals(mock_npe1_pm):
    from napari_plugin_engine import napari_hook_implementation

    class MyPlugin:
        @staticmethod
        @napari_hook_implementation
        def napari_experimental_provide_function():
            def f(x: int): ...

            return [f]

    with pytest.warns(UserWarning) as record:
        mf = manifest_from_npe1(module=MyPlugin)
    msg = str(record[0].message)
    assert "functions defined in local scopes are not yet supported." in msg
    assert isinstance(mf.dict(), dict)


@pytest.mark.filterwarnings("ignore:Failed to convert napari_provide_sample_data")
@pytest.mark.filterwarnings("ignore:Error converting function")
@pytest.mark.filterwarnings("ignore:Error converting dock widget")
def test_conversion_from_package(npe1_repo, mock_npe1_pm_with_plugin):
    setup_cfg = npe1_repo / "setup.cfg"
    before = setup_cfg.read_text()
    convert_repository(npe1_repo, dry_run=True)
    assert setup_cfg.read_text() == before
    assert not (npe1_repo / "npe1_module" / "napari.yaml").exists()
    convert_repository(npe1_repo, dry_run=False)
    new_setup = setup_cfg.read_text()
    assert new_setup != before
    assert (
        "[options.entry_points]\n"
        "napari.manifest = \n	npe1-plugin = npe1_module:napari.yaml"
    ) in new_setup
    assert "[options.package_data]\nnpe1_module = napari.yaml" in new_setup
    assert (npe1_repo / "npe1_module" / "napari.yaml").is_file()

    with pytest.raises(ValueError) as e:
        convert_repository(npe1_repo)
    assert "Is this package already converted?" in str(e.value)


@pytest.mark.filterwarnings("ignore:Failed to convert napari_provide_sample_data")
@pytest.mark.filterwarnings("ignore:Error converting function")
@pytest.mark.filterwarnings("ignore:Error converting dock widget")
def test_conversion_from_package_editable(npe1_repo, mock_npe1_pm_with_plugin_editable):
    setup_cfg = npe1_repo / "setup.cfg"
    before = setup_cfg.read_text()
    convert_repository(npe1_repo, dry_run=True)
    assert setup_cfg.read_text() == before
    assert not (npe1_repo / "npe1_module" / "napari.yaml").exists()
    convert_repository(npe1_repo, dry_run=False)
    new_setup = setup_cfg.read_text()
    assert new_setup != before
    assert (
        "[options.entry_points]\n"
        "napari.manifest = \n	npe1-plugin = npe1_module:napari.yaml"
    ) in new_setup
    assert "[options.package_data]\nnpe1_module = napari.yaml" in new_setup
    assert (npe1_repo / "npe1_module" / "napari.yaml").is_file()

    with pytest.raises(ValueError) as e:
        convert_repository(npe1_repo)
    assert "Is this package already converted?" in str(e.value)


def _assert_expected_errors(record: pytest.WarningsRecorder):
    assert len(record) == 4
    msg = str(record[0].message)
    assert "Error converting dock widget [2] from 'npe1_module'" in msg
    msg = str(record[1].message)
    assert "Error converting function [1] from 'npe1_module'" in msg
    msg = str(record[2].message)
    assert "Failed to convert napari_provide_sample_data in 'npe1-plugin'" in msg
    assert "could not get resolvable python name" in msg
    msg = str(record[3].message)
    assert "Cannot auto-update setup.py, please edit setup.py as follows" in msg
    assert "npe1-plugin = npe1_module:napari.yaml" in msg


def test_conversion_from_package_setup_py(npe1_repo, mock_npe1_pm_with_plugin):
    (npe1_repo / "setup.cfg").unlink()
    (npe1_repo / "setup.py").write_text(
        """from setuptools import setup

NAME = 'npe1-plugin'
setup(
    name=NAME,
    entry_points={"napari.plugin": ["npe1-plugin = npe1_module"]}
)
"""
    )
    with pytest.warns(UserWarning) as record:
        convert_repository(npe1_repo)
    _assert_expected_errors(record)


def test_conversion_entry_point_string(npe1_repo, mock_npe1_pm_with_plugin):
    (npe1_repo / "setup.cfg").unlink()
    (npe1_repo / "setup.py").write_text(
        """from setuptools import setup

setup(
    name='npe1-plugin',
    entry_points={"napari.plugin": "npe1-plugin = npe1_module"}
)
"""
    )
    with pytest.warns(UserWarning) as record:
        convert_repository(npe1_repo)
    _assert_expected_errors(record)


def test_conversion_missing():
    with pytest.raises(
        PackageNotFoundError,
        match="No package or entry point found with name",
    ):
        manifest_from_npe1("does-not-exist-asdf6as987")


def test_conversion_package_is_not_a_plugin():
    with pytest.raises(
        PackageNotFoundError,
        match="No package or entry point found with name",
    ):
        manifest_from_npe1("pytest")


def test_get_top_module_path(mock_npe1_pm_with_plugin):
    get_top_module_path("npe1-plugin")


def test_python_name_local():
    def f():
        return lambda x: None

    with pytest.raises(ValueError) as e:
        _from_npe1._python_name(f())

    assert "functions defined in local scopes are not yet supported" in str(e.value)


def test_guess_fname_patterns():
    def get_reader1(path):
        if isinstance(path, str) and path.endswith((".tiff", ".tif")):
            return 1

    def get_reader2(path):
        if path.endswith(".xyz"):
            return 1

    assert _from_npe1._guess_fname_patterns(get_reader1) == ["*.tiff", "*.tif"]
    assert _from_npe1._guess_fname_patterns(get_reader2) == ["*.xyz"]