File: conftest.py

package info (click to toggle)
python-npe2 0.7.8-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 828 kB
  • sloc: python: 7,088; makefile: 19
file content (226 lines) | stat: -rw-r--r-- 6,825 bytes parent folder | download
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
import shutil
import sys
from importlib import abc, metadata
from pathlib import Path
from unittest.mock import patch

import pytest

from npe2 import PluginManager, PluginManifest
from npe2.manifest import _npe1_adapter

FIXTURES = Path(__file__).parent / "fixtures"


@pytest.fixture
def sample_path():
    return Path(__file__).parent / "sample"


@pytest.fixture
def sample_manifest(sample_path):
    return PluginManifest.from_file(sample_path / "my_plugin" / "napari.yaml")


@pytest.fixture
def compiled_plugin_dir(tmp_path):
    shutil.copytree(FIXTURES / "my-compiled-plugin", tmp_path, dirs_exist_ok=True)
    return tmp_path


@pytest.fixture
def uses_sample_plugin(sample_path):
    sys.path.append(str(sample_path))
    try:
        pm = PluginManager.instance()
        pm.discover()
        yield
    finally:
        sys.path.remove(str(sample_path))


@pytest.fixture
def plugin_manager():
    pm = PluginManager()
    pm.discover()
    return pm


@pytest.fixture(autouse=True)
def mock_discover():
    _discover = PluginManifest.discover

    def wrapper(*args, **kwargs):
        before = sys.path.copy()
        # only allowing things from test directory in discover
        sys.path = [x for x in sys.path if str(Path(__file__).parent) in x]
        try:
            yield from _discover(*args, **kwargs)
        finally:
            sys.path = before

    with patch("npe2.PluginManifest.discover", wraps=wrapper):
        yield 1


@pytest.fixture
def npe1_repo():
    return Path(__file__).parent / "npe1-plugin"


@pytest.fixture
def uses_npe1_plugin(npe1_repo):
    import site

    class Importer(abc.MetaPathFinder):
        def find_spec(self, *_, **__):
            return None

        def find_distributions(self, ctx, **k):
            if ctx.name == "npe1-plugin":
                pth = npe1_repo / "npe1-plugin-0.0.1.dist-info"
                yield metadata.PathDistribution(pth)
            return

    sys.meta_path.append(Importer())
    sys.path.append(str(npe1_repo))
    try:
        pkgs = [*site.getsitepackages(), str(npe1_repo)]
        with patch("site.getsitepackages", return_value=pkgs):
            yield
    finally:
        sys.path.remove(str(npe1_repo))


@pytest.fixture
def npe1_plugin_module(npe1_repo):
    import sys
    from importlib.util import module_from_spec, spec_from_file_location

    npe1_module_path = npe1_repo / "npe1_module" / "__init__.py"
    spec = spec_from_file_location("npe1_module", npe1_module_path)
    assert spec
    module = module_from_spec(spec)
    sys.modules[spec.name] = module
    spec.loader.exec_module(module)  # type: ignore
    try:
        yield module
    finally:
        del sys.modules[spec.name]


@pytest.fixture
def mock_npe1_pm():
    from napari_plugin_engine import PluginManager, napari_hook_specification

    # fmt: off
    class HookSpecs:
        def napari_provide_sample_data(): ...  # type: ignore
        def napari_get_reader(path): ...
        def napari_get_writer(path, layer_types): ...
        def napari_write_graph(path, data, meta): ...
        def napari_write_image(path, data, meta): ...
        def napari_write_labels(path, data, meta): ...
        def napari_write_points(path, data, meta): ...
        def napari_write_shapes(path, data, meta): ...
        def napari_write_surface(path, data, meta): ...
        def napari_write_vectors(path, data, meta): ...
        def napari_experimental_provide_function(): ...  # type: ignore
        def napari_experimental_provide_dock_widget(): ...  # type: ignore
        def napari_experimental_provide_theme(): ...  # type: ignore
    # fmt: on

    for m in dir(HookSpecs):
        if m.startswith("napari"):
            setattr(HookSpecs, m, napari_hook_specification(getattr(HookSpecs, m)))

    pm = PluginManager("napari")
    pm.add_hookspecs(HookSpecs)

    yield pm


@pytest.fixture
def mock_npe1_pm_with_plugin(npe1_repo, npe1_plugin_module):
    """Mocks a fully installed local repository"""
    from npe2._inspection._from_npe1 import plugin_packages

    mock_dist = metadata.PathDistribution(npe1_repo / "npe1-plugin-0.0.1.dist-info")

    def _dists():
        return [mock_dist]

    def _from_name(name):
        if name == "npe1-plugin":
            return mock_dist
        raise metadata.PackageNotFoundError(name)

    setup_cfg = npe1_repo / "setup.cfg"
    new_manifest = npe1_repo / "npe1_module" / "napari.yaml"
    with patch.object(metadata, "distributions", new=_dists):
        with patch.object(metadata.Distribution, "from_name", new=_from_name):
            cfg = setup_cfg.read_text()
            plugin_packages.cache_clear()
            try:
                yield mock_npe1_pm
            finally:
                plugin_packages.cache_clear()
                setup_cfg.write_text(cfg)
                if new_manifest.exists():
                    new_manifest.unlink()
                if (npe1_repo / "setup.py").exists():
                    (npe1_repo / "setup.py").unlink()


@pytest.fixture
def mock_npe1_pm_with_plugin_editable(npe1_repo, npe1_plugin_module, tmp_path):
    """Mocks a fully installed local repository"""
    from npe2._inspection._from_npe1 import plugin_packages

    dist_path = tmp_path / "npe1-plugin-0.0.1.dist-info"
    shutil.copytree(npe1_repo / "npe1-plugin-0.0.1.dist-info", dist_path)

    record_path = dist_path / "RECORD"

    record_content = record_path.read_text().splitlines()
    record_content.pop(-1)
    record_content.append("__editable__.npe1-plugin-0.0.1.pth")

    with record_path.open("w") as f:
        f.write("\n".join(record_content))

    with open(tmp_path / "__editable__.npe1-plugin-0.0.1.pth", "w") as f:
        f.write(str(npe1_repo))

    mock_dist = metadata.PathDistribution(dist_path)

    def _dists():
        return [mock_dist]

    def _from_name(name):
        if name == "npe1-plugin":
            return mock_dist
        raise metadata.PackageNotFoundError(name)

    setup_cfg = npe1_repo / "setup.cfg"
    new_manifest = npe1_repo / "npe1_module" / "napari.yaml"
    with patch.object(metadata, "distributions", new=_dists):
        with patch.object(metadata.Distribution, "from_name", new=_from_name):
            cfg = setup_cfg.read_text()
            plugin_packages.cache_clear()
            try:
                yield mock_npe1_pm
            finally:
                plugin_packages.cache_clear()
                setup_cfg.write_text(cfg)
                if new_manifest.exists():
                    new_manifest.unlink()
                if (npe1_repo / "setup.py").exists():
                    (npe1_repo / "setup.py").unlink()


@pytest.fixture(autouse=True)
def mock_cache(tmp_path, monkeypatch):
    with monkeypatch.context() as m:
        m.setattr(_npe1_adapter, "ADAPTER_CACHE", tmp_path)
        yield tmp_path