Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions docs/how-to-guides/editable-installs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,61 @@ An alternative build directory can be specified using the
:option:`build-dir` config setting.


Data files
----------

It is relatively common to install data files needed at runtime
alongside the package's Python code or extension modules. For a Python
package named ``package`` this would look like this:

.. TODO the :force: option should be removed once the pygments meson lexer is
updated to fix https://github.com/pygments/pygments/issues/2918

.. literalinclude:: ../../tests/packages/install-data/meson.build
:language: meson
:force:
:lines: 5-

In most circumstances, these files can be accessed deriving their
filesystem path from the filesystem path of the Python module next to
them via the ``__file__`` special variable. For example, within the
package ``__init__.py``:

.. code-block:: python

import pathlib

data = pathlib.Path(__file__).parent.joinpath('data.txt').read_text()
uuid = pathlib.Path(__file__).parent.joinpath('uuid.txt').read_text() # WRONG!

However, this does not work when modules are not loaded from a package
installed in the Python library path in the filesystem but with a
special module loader, as used to implement editable installs in
``meson-python``. In the example above, the second read would fail
when the package is installed in editable mode. For this reason, data
files need to be accessed using :mod:`importlib.resources`. The code
above should be replaced with:

.. literalinclude:: ../../tests/packages/install-data/__init__.py
:lines: 5-

:mod:`importlib.resources` implements a virtual filesystem that allows
to access individual files as if they were in their install location.
However, there is no way to expose this file structure outside of the
python runtime. In the example above, it is not possible to make the
``data.txt`` and ``uuid.txt`` files appear in the same fileystem
directory.

.. warning::

The :mod:`importlib.resources` appeared in Python 3.7 but it did not work
correctly for this use until Python 3.10. The `importlib-resources`_
backport version 5.10 or later can be used if support for earlier Python
versions is desired.

.. _importlib-resources: https://importlib-resources.readthedocs.io/en/latest/index.html


.. _how-to-guides-editable-installs-verbose:

Verbose mode
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ known-first-party = [
'mesonpy',
]

[tool.ruff.lint.per-file-ignores]
# this file is included literally in the documentation and the double
# empty lines forced by the import sorting style look odd there
'tests/packages/install-data/__init__.py' = ['I001']


[tool.coverage.run]
disable_warnings = [
Expand Down
8 changes: 8 additions & 0 deletions tests/packages/install-data/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# SPDX-FileCopyrightText: 2025 The meson-python developers
#
# SPDX-License-Identifier: MIT

import importlib.resources

data = importlib.resources.files(__package__).joinpath('data.txt').read_text()
uuid = importlib.resources.files(__package__).joinpath('uuid.txt').read_text()
1 change: 1 addition & 0 deletions tests/packages/install-data/data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATA
3 changes: 3 additions & 0 deletions tests/packages/install-data/data.txt.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: 2025 The meson-python developers
#
# SPDX-License-Identifier: MIT
25 changes: 25 additions & 0 deletions tests/packages/install-data/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2025 The meson-python developers
#
# SPDX-License-Identifier: MIT

project('package', version: '1.0.0')

py = import('python').find_installation()

py.install_sources(
'__init__.py',
subdir: 'package',
)

install_data(
'data.txt',
install_dir: py.get_install_dir() / 'package',
)

custom_target(
output: 'uuid.txt',
command: [py, '-m', 'uuid'],
capture: true,
install: true,
install_dir: py.get_install_dir() / 'package',
)
7 changes: 7 additions & 0 deletions tests/packages/install-data/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2023 The meson-python developers
#
# SPDX-License-Identifier: MIT

[build-system]
build-backend = 'mesonpy'
requires = ['meson-python']
6 changes: 6 additions & 0 deletions tests/test_editable.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,9 @@ def test_editable_rebuild_error(package_purelib_and_platlib, tmp_path, verbose):
del sys.meta_path[0]
sys.modules.pop('pure', None)
path.write_text(code)


@pytest.mark.skipif(sys.version_info < (3, 10), reason='importlib.resources is unusable on Python 3.9')
def test_install_data(venv, editable_install_data, tmp_path):
venv.pip('install', os.fspath(editable_install_data))
venv.python('-c', 'import package')
Loading