Control: retitle -1 python-npe2: FTBFS: importlib.metadata.MetadataNotFound: No
package metadata was found
On Fri, Oct 23, 2026 at 04:27:46PM +0000, Santiago Vila wrote:
from pydantic_core import __version__ as __pydantic_core_version__
File "/usr/lib/python3/dist-packages/pydantic_core/__init__.py", line 8, in
<module>
from ._pydantic_core import (
...<21 lines>...
)
ImportError: cannot import name 'ArgsKwargs' from
'pydantic_core._pydantic_core' (unknown location)
Now that pydantic-core has been rebuilt against Python 3.15, this fails
in a different way. The Python 3.14 tests are fine. I haven't debugged
this further.
I: pybuild base:383: cd
/build/reproducible-path/python-npe2-0.8.3/.pybuild/cpython3_3.15_npe2/build; python3.15
-m pytest -k "not fetch and not test_cli_convert_svg and not test_conversion and not
test_render_docs and not test_setuptools_plugin and not test_compile and not
test_cli_convert_package_name" tests
============================= test session starts ==============================
platform linux -- Python 3.15.1, pytest-9.1.1, pluggy-1.6.0
rootdir: /build/reproducible-path/python-npe2-0.8.3
configfile: pyproject.toml
plugins: npe2-0.8.3, napari-plugin-engine-0.2.1, pretty-1.3.0
collected 265 items / 59 deselected / 1 skipped / 206 selected
tests/test__io_utils.py .................................. [ 16%]
tests/test_cli.py ................................... [ 33%]
tests/test_config_contribution.py ................ [ 41%]
tests/test_contributions.py ..................... [ 51%]
tests/test_docs.py . [ 51%]
tests/test_implements.py .... [ 53%]
tests/test_manifest.py ....F [ 56%]
.pybuild/cpython3_3.15_npe2/build/tests/test_manifest.py:46 test_discover_errors
tests/test_manifest.py ............ [ 62%]
tests/test_npe1_adapter.py ........ [ 66%]
tests/test_package_meta.py ... [ 67%]
tests/test_plugin_manager.py ................ [ 75%]
tests/test_pm_module.py . [ 75%]
tests/test_pytest_plugin.py F [ 76%]
.pybuild/cpython3_3.15_npe2/build/tests/test_pytest_plugin.py:60
test_npe2pm_fixture[\nfrom npe2._pytest_plugin import TestPluginManager\nfrom
npe2 import PluginManager\n\ndef test_something_1(npe2pm):\n assert
isinstance(npe2pm, TestPluginManager)\n assert PluginManager.instance() is
npe2pm\n]
tests/test_pytest_plugin.py ..... [ 78%]
tests/test_tmp_plugin.py ... [ 80%]
tests/test_utils.py .... [ 82%]
tests/test_validations.py ..................................... [100%]
=================================== FAILURES ===================================
_____________________________ test_discover_errors _____________________________
cls = <class 'npe2.manifest.schema.PluginManifest'>
paths = [PosixPath('/tmp/pytest-of-sbuild/pytest-0/test_discover_errors0')]
@classmethod
def discover(cls, paths: Sequence[str | Path] = ()) ->
Iterator[DiscoverResults]:
"""Discover manifests in the environment.
This function searches for installed python packages with a matching
entry point group and then attempts to resolve the manifest file.
The manifest file should be specified in the plugin's ``setup.cfg`` or
``setup.py`` file using the [entry point group][1]: "napari.manifest".
For example, this would be the section for a plugin "npe-tester" with
"napari.yaml" as the manifest file:
.. code-block:: cfg
[options.entry_points]
napari.manifest =
npe2-tester = npe2_tester:napari.yaml
The manifest file is specified relative to the submodule root path.
So for the example it will be loaded from:
``<path/to/npe2-tester>/napari.yaml``.
[1]: https://packaging.python.org/specifications/entry-points/
Parameters
----------
paths : Sequence[str], optional
paths to add to sys.path while discovering.
Yields
------
DiscoverResults: (3 namedtuples: manifest, entrypoint, error)
3-tuples with either manifest or (entrypoint and error) being None.
"""
with _temporary_path_additions(paths):
for dist in metadata.distributions():
try:
pm = _from_dist(dist)
^^^^^^^^^^^^^^^^
npe2/manifest/schema.py:367:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
npe2/manifest/schema.py:554: in _from_dist
return PluginManifest._from_entrypoint(_npe2, dist)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cls = <class 'npe2.manifest.schema.PluginManifest'>
entry_point = EntryPoint(name='my-plugin', value='asdfsad:blahblahblah.yaml',
group='napari.manifest')
distribution = <importlib.metadata.PathDistribution object at 0x7ff488cd5130>
@classmethod
def _from_entrypoint(
cls,
entry_point: metadata.EntryPoint,
distribution: metadata.Distribution | None = None,
) -> PluginManifest:
module_match = entry_point.pattern.match(entry_point.value)
assert module_match is not None
module = module_match.group("module")
spec = util.find_spec(module or "")
if not spec: # pragma: no cover
raise ValueError(
f"Cannot find module {module!r} declared in "
f"entrypoint: {entry_point.value!r}"
)
E ValueError: Cannot find module 'asdfsad' declared in entrypoint:
'asdfsad:blahblahblah.yaml'
npe2/manifest/schema.py:399: ValueError
During handling of the above exception, another exception occurred:
tmp_path = PosixPath('/tmp/pytest-of-sbuild/pytest-0/test_discover_errors0')
@pytest.mark.filterwarnings("ignore:Implicit None on return values is
deprecated")
def test_discover_errors(tmp_path: Path):
"""testing various discovery errors"""
# package with proper `napari.manifest` entry_point, but invalid
pointer to
# a manifest should yield an error in results
a = tmp_path / "a"
a.mkdir()
a_ep = a / "entry_points.txt"
bad_value = "asdfsad:blahblahblah.yaml"
a_ep.write_text(f"[napari.manifest]\n{SAMPLE_PLUGIN_NAME} =
{bad_value}")
# package with proper `napari.manifest` entry_point, but invalid
manifest
b = tmp_path / "b"
b.mkdir()
b_ep = b / "entry_points.txt"
b_ep.write_text("[napari.manifest]\nsome_plugin = module:napari.yaml")
module = tmp_path / "module"
module.mkdir()
(module / "napari.yaml").write_text("name: hi??")
# a regular package, with out napari.manifest entry_point should just
be skipped
c = tmp_path / "c"
c.mkdir()
c_ep = c / "entry_points.txt"
c_ep.write_text("[console.scripts]\nsomething = something")
dists = [
metadata.PathDistribution(a),
metadata.PathDistribution(b),
metadata.PathDistribution(c),
]
with patch.object(metadata, "distributions", return_value=dists):
discover_results = list(PluginManifest.discover(paths=[tmp_path]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/test_manifest.py:80:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tests/conftest.py:62: in wrapper
yield from _discover(*args, **kwargs)
npe2/manifest/schema.py:382: in discover
ENTRY_POINT, dist.metadata["Name"], e
^^^^^^^^^^^^^
/usr/lib/python3.15/importlib/metadata/__init__.py:543: in metadata
return self._assemble_message(self._ensure_metadata_present(text))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <importlib.metadata.PathDistribution object at 0x7ff488cd5130>
text = None
def _ensure_metadata_present(self, text: str | None) -> str:
if text is not None:
return text
raise MetadataNotFound('No package metadata was found.')
E importlib.metadata.MetadataNotFound: No package metadata was found.
/usr/lib/python3.15/importlib/metadata/__init__.py:556: MetadataNotFound
_ test_npe2pm_fixture[\nfrom npe2._pytest_plugin import TestPluginManager\nfrom
npe2 import PluginManager\n\ndef test_something_1(npe2pm):\n assert
isinstance(npe2pm, TestPluginManager)\n assert PluginManager.instance() is
npe2pm\n] _
pytester_pretty = <pytest_pretty.PytesterWrapper object at 0x7ff486d0a7b0>
case = '\nfrom npe2._pytest_plugin import TestPluginManager\nfrom npe2 import
PluginManager\n\ndef test_something_1(npe2pm):\n assert isinstance(npe2pm,
TestPluginManager)\n assert PluginManager.instance() is npe2pm\n'
@pytest.mark.parametrize("case", [CASE1, CASE2, CASE3, CASE4, CASE5, CASE6])
def test_npe2pm_fixture(pytester_pretty: pytest.Pytester, case):
"""Make sure that the npe2pm fixture works."""
# create a temporary pytest test file
pytester_pretty.makepyfile(case)
pytester_pretty.runpytest().assert_outcomes(passed=1)
E AssertionError: assert {'passed': 0,...rors': 0, ...} == {'passed':
1,...rors': 0, ...}
E
E Omitting 5 identical items, use -vv to show
E Differing items:
E {'passed': 0} != {'passed': 1}
E Use -v to get more diff
/build/reproducible-path/python-npe2-0.8.3/.pybuild/cpython3_3.15_npe2/build/tests/test_pytest_plugin.py:67:
AssertionError
----------------------------- Captured stdout call -----------------------------
============================= test session starts ==============================
platform linux -- Python 3.15.1, pytest-9.1.1, pluggy-1.6.0
rootdir: /tmp/pytest-of-sbuild/pytest-0/test_npe2pm_fixture0
plugins: npe2-0.8.3, napari-plugin-engine-0.2.1, pretty-1.3.0
collected 1 item / 1 error
==================================== ERRORS ====================================
___________________ ERROR collecting test_npe2pm_fixture.py ____________________
/usr/lib/python3/dist-packages/_pytest/runner.py:361: in from_call
result: TResult | None = func()
^^^^^^
/usr/lib/python3/dist-packages/_pytest/runner.py:406: in collect
return list(collector.collect())
^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/_pytest/python.py:762: in collect
self.warn(
/usr/lib/python3/dist-packages/_pytest/nodes.py:263: in warn
warnings.warn_explicit(
E pytest.PytestCollectionWarning: cannot collect test class
'TestPluginManager' because it has a __init__ constructor (from:
test_npe2pm_fixture.py)
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
Results (0.07s):
1 error
============================= slowest 10 durations =============================
0.11s call
.pybuild/cpython3_3.15_npe2/build/tests/test_cli.py::test_cli_validate_load_err
0.08s call
.pybuild/cpython3_3.15_npe2/build/tests/test_pytest_plugin.py::test_npe2pm_fixture[\nfrom
npe2._pytest_plugin import TestPluginManager\nfrom npe2 import
PluginManager\n\ndef test_something_1(npe2pm):\n assert isinstance(npe2pm,
TestPluginManager)\n assert PluginManager.instance() is npe2pm\n]
0.04s call
.pybuild/cpython3_3.15_npe2/build/tests/test_npe1_adapter.py::test_npe1_adapter_cache
0.03s call
.pybuild/cpython3_3.15_npe2/build/tests/test_pytest_plugin.py::test_npe2pm_fixture[\nimport
pytest\n\ndef test_something_6(npe2pm):\n with
pytest.raises(FileNotFoundError):\n
npe2pm.tmp_plugin(manifest='some_path.yaml')\n]
0.03s call
.pybuild/cpython3_3.15_npe2/build/tests/test_cli.py::test_cli_parse[False-toml]
0.03s call
.pybuild/cpython3_3.15_npe2/build/tests/test_cli.py::test_cli_parse[False-yaml]
0.03s call
.pybuild/cpython3_3.15_npe2/build/tests/test_cli.py::test_cli_parse[True-yaml]
0.03s call
.pybuild/cpython3_3.15_npe2/build/tests/test_contributions.py::test_writer_priority
0.02s call
.pybuild/cpython3_3.15_npe2/build/tests/test_npe1_adapter.py::test_npe1_adapter
0.02s call
.pybuild/cpython3_3.15_npe2/build/tests/test__io_utils.py::test_read_uses_correct_passed_plugin
Summary of Failures
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ � ┃ Function ┃ ┃ ┃
┃ File ┃ Function ┃ Line ┃ Error Line ┃ Error ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ .pybuild/c… │ test_disco… │ 47 │ 80 │ MetadataNo… │
│ .pybuild/c… │ test_npe2p… │ 61 │ 67 │ AssertionE… │
│ │ npe2._pyte… │ │ │ │
│ │ import │ │ │ │
│ │ TestPlugin… │ │ │ │
│ │ npe2 import │ │ │ │
│ │ PluginMana… │ │ │ │
│ │ test_somet… │ │ │ │
│ │ assert │ │ │ │
│ │ isinstance… │ │ │ │
│ │ TestPlugin… │ │ │ │
│ │ assert │ │ │ │
│ │ PluginMana… │ │ │ │
│ │ is │ │ │ │
│ │ npe2pm\n] │ │ │ │
└───────────────┴───────────────┴───────────────┴──────────────┴───────────────┘
Results (0.32s):
2 failed
204 passed
1 skipped
59 deselected
E: pybuild pybuild:485: test: plugin pyproject failed with: exit code=1: cd
/build/reproducible-path/python-npe2-0.8.3/.pybuild/cpython3_3.15_npe2/build; python3.15
-m pytest -k "not fetch and not test_cli_convert_svg and not test_conversion and not
test_render_docs and not test_setuptools_plugin and not test_compile and not
test_cli_convert_package_name" tests
--
Colin Watson (he/him) [[email protected]]