././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/.cirrus.yml0000644000000000000000000000266214516424013013363 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT test_template: &test test_script: - command -v python3 - python3 --version - python3 -m venv env - . env/bin/activate - python3 -m pip install .[test] - python3 -m pytest alpine-3_task: container: dockerfile: ci/alpine-3.docker cpu: 1 << : *test archlinux_task: container: dockerfile: ci/archlinux.docker cpu: 1 << : *test debian-11_task: container: dockerfile: ci/debian-11.docker cpu: 1 << : *test debian-12_task: container: dockerfile: ci/debian-12.docker cpu: 1 << : *test debian-unstable_task: container: dockerfile: ci/debian-unstable.docker cpu: 1 << : *test fedora-37_task: container: dockerfile: ci/fedora-37.docker cpu: 1 << : *test manylinux-python3.11_task: container: dockerfile: ci/manylinux.docker cpu: 1 env: PATH: "/opt/python/cp311-cp311/bin/:${PATH}" << : *test manylinux-python3.7_task: container: dockerfile: ci/manylinux.docker cpu: 1 env: PATH: "/opt/python/cp37-cp37m/bin/:${PATH}" << : *test miniconda_task: container: dockerfile: ci/miniconda.docker cpu: 1 << : *test opensuse-15_task: container: dockerfile: ci/opensuse-15.docker cpu: 1 << : *test freebsd_task: freebsd_instance: image_family: freebsd-13-2 install_script: pkg install -y git ninja << : *test ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/.github/workflows/docs.yml0000644000000000000000000000077414516424013016325 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT name: docs on: push: pull_request: branches: - main - release-* paths: - docs/** - CHANGELOG.rst - README.md jobs: docs: runs-on: ubuntu-latest steps: - uses: actions/setup-python@v4 with: python-version: '3.11' - uses: actions/checkout@v3 - run: python -m pip install .[docs] - run: python -m sphinx docs/ build/docs/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/.github/workflows/tests.yml0000644000000000000000000002103414516424013016527 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT name: tests on: push: pull_request: branches: - main - release-* paths: # This is spelt like this to do not ignore the docs/examples/ folder. - '**' - '!docs/**' - 'docs/examples/**' - '!CHANGELOG.rst' - '!LICENSE' - '!LICENSES/**' - '!README.rst' workflow_dispatch: # Allow to run manually env: FORCE_COLOR: 1 PIP_DISABLE_PIP_VERSION_CHECK: 1 concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: test: runs-on: ${{ matrix.os }}-latest strategy: fail-fast: false matrix: os: - ubuntu - macos - windows python: - '3.7' - '3.12' meson: - include: - os: ubuntu python: 'pypy-3.9' - os: ubuntu python: 'pypy-3.10' - os: ubuntu python: '3.8' - os: ubuntu python: '3.9' - os: ubuntu python: '3.10' # Test with older supported Meson version. Meson up to # version 1.2.3 requires distutils, which has been removed # from the stdlib in Python 3.12, thus test with Pythn 3.11. - os: ubuntu python: '3.11' meson: '~=0.63.3' - os: ubuntu python: '3.11' meson: '~=0.64.0' - os: ubuntu python: '3.11' meson: '~=1.0.0' - os: ubuntu python: '3.11' meson: '~=1.1.0' # Test with Meson master branch. - os: ubuntu python: '3.12' meson: '@git+https://github.com/mesonbuild/meson.git' - os: windows python: '3.12' meson: '@git+https://github.com/mesonbuild/meson.git' steps: - name: Checkout uses: actions/checkout@v3 - name: Set up target Python uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Install Ninja run: sudo apt-get install ninja-build if: ${{ matrix.os == 'ubuntu' }} - name: Install Ninja run: brew install ninja if: ${{ matrix.os == 'macos' }} - name: Install Ninja run: python -m pip install ninja if: ${{ matrix.os == 'windows' }} - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install run: python -m pip install .[test] - name: Run tests run: >- python -m pytest --showlocals -vv --cov --cov-report=xml - name: Upload coverage report uses: codecov/codecov-action@v3 if: ${{ always() }} msvc: runs-on: windows-latest strategy: fail-fast: false matrix: python: - '3.11' meson: - steps: - name: Checkout uses: actions/checkout@v3 - name: Set up target Python uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Install Ninja run: python -m pip install ninja - name: Setup MSVC uses: bus1/cabuild/action/msdevshell@e22aba57d6e74891d059d66501b6b5aed8123c4d # v1 with: architecture: x64 - name: Install Meson run: python -m pip install "meson==${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install run: python -m pip install .[test] - name: Run tests run: >- python -m pytest --showlocals -vv cygwin: runs-on: windows-latest strategy: fail-fast: false matrix: python: - '3.9' meson: - steps: - name: Checkout uses: actions/checkout@v3 - name: Setup Cygwin uses: cygwin/cygwin-install-action@v2 with: packages: >- python39 python39-devel python39-pip python39-setuptools cmake gcc-core gcc-g++ git make ninja - name: Fix git dubious ownership # This addresses the "fatal: detected dubious ownership in # repository" and "fatal: not in a git directory" errors # encountered when trying to run Cygwin git in a directory not # owned by the current user. This happens when the tests run # Cygwin git in a directory outside the Cygwin filesystem. run: git config --global --add safe.directory '*' shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} - name: Get pip cache path id: pip-cache-path run: echo "path=$(cygpath -w $(python -m pip cache dir))" >> $GITHUB_OUTPUT shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} - name: Restore cache # Cygwin Python cannot use binary wheels from PyPI. Building # some dependencies takes considerable time. Caching the built # wheels speeds up the CI job quite a bit. uses: actions/cache@v3 with: path: ${{ steps.pip-cache-path.outputs.path }} key: cygwin-pip-${{ github.sha }} restore-keys: cygwin-pip- - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} - name: Install # Cygwin patches Python's ensurepip module to look for the # wheels needed to initialize a new virtual environment in # /usr/share/python-wheels/ but nothing in Cygwin actually # puts the setuptools and pip wheels there. Fix this. run: | mkdir /usr/share/python-wheels/ pushd /usr/share/python-wheels/ python -m pip download setuptools pip popd python -m pip install .[test] shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} - name: Run tests run: >- python -m pytest --showlocals -vv shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} pyston: runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: python: - '3.8' meson: - steps: - name: Checkout uses: actions/checkout@v3 - name: Install pyston run: | wget https://github.com/pyston/pyston/releases/download/pyston_2.3.5/pyston_2.3.5_20.04_amd64.deb sudo apt install $(pwd)/pyston_2.3.5_20.04_amd64.deb - name: Install Ninja run: sudo apt-get install ninja-build - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install run: pyston -m pip install .[test] - name: Run tests run: >- pyston -m pytest --showlocals -vv homebrew: runs-on: macos-latest strategy: fail-fast: false matrix: python: - '3.8' - '3.11' meson: - steps: - name: Checkout uses: actions/checkout@v3 - name: Install Homebrew Python run: | brew install --overwrite python@${{ matrix.python }} echo /usr/local/opt/python@${{ matrix.python }}/libexec/bin/ >> $GITHUB_PATH - name: Install Ninja run: brew install ninja - name: Update pip # pip >= 23.0 fixes https://github.com/pypa/pip/issues/11539 run: python -m pip install --upgrade "pip >= 23.0" - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install run: python -m pip install .[test] - name: Run tests run: >- python -m pytest --showlocals -vv mypy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Setup Python uses: actions/setup-python@v4 with: python-version: 3.9 - name: Install dependencies run: python -m pip install . - name: Install mypy run: python -m pip install mypy==1.5.1 - name: Run mypy run: mypy -p mesonpy ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/.gitignore0000644000000000000000000000025214516424013013234 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT .mesonpy-native-file.ini .mesonpy/ docs/_build *.pyc .cache/ dist/ .coverage ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/.mailmap0000644000000000000000000000024714516424013012671 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT Matthias Köppe Yue Yang ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/.pre-commit-config.yaml0000644000000000000000000000176714516424013015541 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT ci: autofix_prs: false autoupdate_commit_msg: 'MAINT: bump repositories' repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: check-ast - id: check-builtin-literals - id: check-docstring-first - id: check-merge-conflict - id: check-yaml - id: check-toml - id: debug-statements - id: double-quote-string-fixer - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/PyCQA/isort rev: 5.12.0 hooks: - id: isort - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.0.261 hooks: - id: ruff args: [--fix, --show-fixes, --format, grouped] - repo: https://github.com/fsfe/reuse-tool rev: v1.1.2 hooks: - id: reuse name: add SPDX headers args: [annotate, --skip-existing, --skip-unrecognised, --copyright=The meson-python developers, --license=MIT] pass_filenames: true - id: reuse name: reuse lint ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/.readthedocs.yml0000644000000000000000000000031414516424013014331 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT version: 2 python: version: 3.8 install: - method: pip path: . extra_requirements: [docs] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/CHANGELOG.rst0000644000000000000000000002430714516424013013274 0ustar00.. SPDX-FileCopyrightText: 2021 The meson-python developers .. .. SPDX-License-Identifier: MIT .. Contributors list for the latest release can be generated with git log --format='%aN' $PREV..HEAD | sort -u | awk '$1=$1' RS='' FS='\n' OFS=', ' +++++++++ Changelog +++++++++ 0.15.0 ====== - Enable compression for wheel files. The may result in several times smaller wheels. - Require Meson 1.2.3 or later on Python 3.12 or later. Meson 1.2.3 does not require anymore ``distutils``, allowing to remove the dependency on ``setuptools`` on Python 3.12 or later. - Unconditionally require ``patchelf`` on Linux. The ``patchelf`` package is added to the build dependencies if a suitable ``patchelf`` executable is not find on the ``$PATH``. This avoids cases where ``meson setup`` was run twice during the build process to determine whether ``patchelf`` is required. - Allow to configure the ``meson`` executable to use for the build process through the ``$MESON`` environment variable or the ``meson`` key under ``[tool.meson-python]`` in ``pyproject.toml``. - Fix wheel platform tag generation on FreeBSD. - Extend support to other UNIX-like systems and make the tests pass on FreeBSD. - Fix package name normalization in package metadata and improve package name validation. - Fix ``RPATH`` handling when the build ``RPATH`` points to subdirectories of the build directory. - Fix support for the Python limited C API when compiling for PyPy. - Rename the ``builddir`` config-setting to ``build-dir``. For backwards compatibility, the ``buildir`` config-setting remains supported as an alias. Christoph Reiter, Daniele Nicolodi, Elliott Sales de Andrade, Ralf Gommers, Yue Yang --- 26-10-2023 0.14.0 ====== - Do not run ``meson install`` to build a wheel. This was unnecessary as files are added to the wheel from the build and source directories. This does not affect the handling of ``meson install`` options, which are interpreted by ``meson-python`` itself. - Obey the ``--skip-subprojects`` when specified for the ``meson install`` command. - Implement support for the ``exclude_directories`` and ``exclude_files`` arguments to Meson ``install_subdir()`` function and similar installation functions. This requires Meson version 1.1.0 or later. - Implement support for building wheels targeting the Python limited API. Extension modules targeting the Python limited API can be easily built starting with the upcoming Meson 1.3.0 release. - When ``pyproject.toml`` does not contain a ``version`` field and ``version`` is not declared dynamic, raise an error instead of silently using the version declared in ``meson.build``. - Fix the mtime of source files in the sdist tarball. - Add ``objc`` and ``objcpp`` compilers to the cross file generated when the ``$ARCHFLAGS`` is set. - Extensive documentation improvements. Charles Brunet, Daniele Nicolodi, Henry Schreiner, Michał Górny, Ralf Gommers --- 05-09-2023 0.13.2 ====== - Fix system name in cross file generated when using ``$ARCHFLAGS``. - Fix handling of ``null`` Meson install tags. Charles Brunet, Daniele Nicolodi --- 22-06-2023. 0.13.1 ====== - Fix regression in cross-compilation via ``$ARCHFLAGS`` on macOS where the cross file was written in the build directory before it was created, resulting in an error. - Do not require setting ``$_PYTHON_HOST_PLATFORM`` when cross-compiling via ``$ARCHFLAGS`` on macOS. - Add the ``--quiet`` option when invoking ``meson install``. The installation paths are a detail of the ``meson-python`` implementation and are generally not interesting for the user. - Fix terminal logging when overriding the current line when listing files added to the wheel. - Improve the error message emitted when a package split between the ``purelib`` and ``platlib`` wheel locations is detected. Daniele Nicolodi, Ralf Gommers --- 28-04-2023. 0.13.0 ====== - Add support for editable installs. - Adjust the default build options passed to ``meson setup``. - Make sure that the directory where the wheel or sdist build artifacts are created exists. Fixes building with PDM. - Fix the specification of the C++ compiler for cross-compilation with ``$ARCHFLAGS`` on macOS. - Pass the ``--reconfigure`` option to ``meson setup`` if and only if the specified build directory exists and is a valid Meson build directory. - Pass the ``--no-rebuild`` option to ``meson install``. - Allow to select the files to be included in the wheel via Meson install tags passing the ``--tags`` option to ``meson install`` via ``pyproject.toml`` or config settings. - Do not use the ``meson compile`` indirection to build the project, except on Windows, where it is required to setup the Visual Studio environment. - Do not add ``ninja`` to the build dependencies if ``$NINJA`` is set but it does not point to a ``ninja`` executable with the required minimum version. - Verify at run time that Meson satisfies the minimum required version. - Place native and cross files in the build directory instead of in the source directory. - Drop the ``typing-extensions`` package dependency. - Add dependency on ``setuptools`` on Python 3.12 and later. This fixes build error due to Meson depending on the ``distutils`` standard library module removed in Python 3.12. - Bump the required ``pyproject-metadata`` version to 0.7.1. - Allows some more cross-compilation setups by not checking extension modules filename suffixes against the suffixes accepted by the current interpreter. - Raise an error when a file that would be installed by Meson cannot be mapped to a wheel location. - Raise an error when a package is split between ``platlib`` and ``purelib``. - Do not generate a warning when ``pyproject.toml`` does not contain a ``project`` section and Python package metadata is derived from ``meson.build``. - Improve reporting of ``pyproject.toml`` validation errors. - Fix validation of tool specific options in ``pyproject.toml``. In particular, allows to specify an incomplete set of options in the ``tool.meson-python.args`` table. Daniele Nicolodi, Doron Behar, Eli Schwartz, Filipe Laíns, Lars Pastewka, Luigi Giugliano, Matthias Köppe, Peter Urban, Ralf Gommers, Stefan van der Walt, Thomas Li --- 18-04-2023. 0.12.1 ====== - Fix regression where the ``$MACOSX_DEPLOYMENT_TARGET`` environment variable was accidentally renamed to ``$MACOS_DEPLOYMENT_TARGET``. Filipe Laíns, Stefan van der Walt --- 17-02-2023. 0.12.0 ====== - Require the ``typing_extensions`` package for Python < 3.10 rather than for Python < 3.8 only. - Emit an error message and raise ``SystemExit`` on expected errors. - Revise error messages for consistency. - Support setuptools-style macOS cross compilation via ``$ARCHFLAGS``. - Allow to overwrite macOS platform tag via ``$_PYTHON_HOST_PLATFORM``. - Include an hint with the most similar known option names in the error message emitted when an unknown config setting is encountered. Daniele Nicolodi, Filipe Laíns, Henry Schreiner, Matthias Köppe, Thomas A Caswell --- 22-12-2022. 0.11.0 ====== - Project moved to the ``mesonbuild`` organization. - Determine wheel tags by introspecting the Python interpreter. - Allow users to pass options directly to Meson via the ``dist``, ``setup``, ``compile``, and ``install`` entries in the ``tools.meson-python.args`` table in ``pyproject.toml``, or via the ``dist-args``, ``setup-args``, ``compile-args``, and ``install-args`` config settings. - Use the system ``ninja`` if possible. Return ``ninja`` as a build dependency otherwise. - Include files generated by ``mesonadd_dist_script`` in the sdist. - Use ``tomllib`` on Python 3.11 or later. - Drop the ``wheel`` package dependency. - Fix bug where the ``entry_points.txt`` file was not generated. - Fix bug where Cygwin Python extensions were not being noticed. Ben Greiner, Daniele Nicolodi, Filipe Laíns, Henry Schreiner, Matthias Köppe, Ralf Gommers, Sam Thursfield, Thomas Li --- 21-11-2022. 0.10.0 ====== - Ignore the minor version on macOS 11 or later, to match the behavior of ``pypa/packaging``. Filipe Laíns, Ralf Gommers --- 05-10-2022. 0.9.0 ===== - More fixes on ABI tag detection. - Fix incorrect tag on 32-bit Python running on a x86_64 host. - Fix sdist permissions. - Fix incorrect PyPy tags. - Fix ``install_subdirs`` not being included in wheels. - Take ``MACOSX_DEPLOYMENT_TARGET`` into account for the platform tag. - Don't set the rpath on binaries if unneeded. Eli Schwartz, Filipe Laíns, Matthias Köppe, Peyton Murray, Ralf Gommers, Thomas Kluyver, Thomas Li --- 29-09-2022. 0.8.1 ===== - Fix ``UnboundLocalError`` in tag detection code. Filipe Laíns, Ralf Gommers --- 28-07-2022. 0.8.0 ===== - Fix sometimes the incorrect ABI tags being generated. - Add workaround for macOS 11 and 12 installations that are missing a minor version in the platform string. Filipe Laíns --- 26-07-2022. 0.7.0 ===== - Fix the wrong Python and ABI tags being generated in Meson 0.63.0. - Fix project license not being included in the project metadata. Filipe Laíns, Ralf Gommers --- 22-07-2022. 0.6.0 ===== - Project re-licensed to MIT. - Error out when running in an unsupported interpreter. - Fix slightly broken Debian heuristics. - Update ``pep621`` dependency to ``pyproject-metadata``. Filipe Laíns, Ralf Gommers, Thomas A Caswell --- 21-06-2022. 0.5.0 ===== - Improvements in dependency detections. - Include uncommited changes in sdists. Filipe Laíns --- 26-05-2022. 0.4.0 ===== - Set sane default arguments for release builds. Filipe Laíns --- 06-05-2022. 0.3.0 ===== - Initial cross-platform support. - Bundling libraries is still only supported on Linux. - Add initial documentation. - The build directory is now located in the project source. Filipe Laíns, Rafael Silva --- 23-03-2022. 0.2.1 ===== - Fix getting the project version dynamically from Meson. Filipe Laíns --- 26-02-2022. 0.2.0 ===== - Select the correct ABI and Python tags. - Force Meson to use the correct Python executable. - Replace auditwheel with in-house vendoring mechanism. Filipe Laíns --- 24-01-2022. 0.1.2 ===== - Fix auditwheel not being run. Filipe Laíns --- 12-11-2021. 0.1.1 ===== - Fix minor compatibility issue with Python < 3.9. Filipe Laíns --- 28-10-2021. 0.1.0 ===== - Initial release. Filipe Laíns --- 28-10-2021. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/LICENSE0000644000000000000000000000220314516424013012247 0ustar00Copyright © 2022 the meson-python contributors Copyright © 2021 Quansight Labs and Filipe Laíns Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/LICENSES/MIT.txt0000644000000000000000000000220314516424013013641 0ustar00Copyright © 2022 the meson-python contributors Copyright © 2021 Quansight Labs and Filipe Laíns Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/README.rst0000644000000000000000000000173414516424013012741 0ustar00.. SPDX-FileCopyrightText: 2021 The meson-python developers .. SPDX-License-Identifier: MIT meson-python ============ ``meson-python`` is a Python build backend built on top of the Meson__ build system. It enables to use Meson for the configuration and build steps of Python packages. Meson is an open source build system meant to be both extremely fast, and, even more importantly, as user friendly as possible. ``meson-python`` is best suited for building Python packages containing extension modules implemented in languages such as C, C++, Cython, Fortran, Pythran, or Rust. Consult the documentation__ for more details. Questions regarding the use of ``meson-python`` can be directed to the discussions__ space on GitHub. Bug reports and feature requests can be filed as GitHub issues__. __ https://mesonbuild.com/ __ https://meson-python.readthedocs.io/en/latest/ __ https://github.com/mesonbuild/meson-python/discussions/ __ https://github.com/mesonbuild/meson-python/issues/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/ci/alpine-3.docker0000644000000000000000000000027714516424013014447 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20221203 FROM alpine:3 RUN apk add --no-cache python3-dev py3-pip build-base ninja git patchelf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/ci/archlinux.docker0000644000000000000000000000033414516424013015026 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20221203 FROM archlinux:latest RUN pacman -Syu --noconfirm && pacman -S --noconfirm python python-pip gcc ninja git patchelf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/ci/debian-11.docker0000644000000000000000000000036714516424013014500 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20221203 FROM debian:bullseye RUN apt-get update && apt-get install -y git ninja-build patchelf python3-pip python3-venv && rm -rf /var/lib/apt/lists/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/ci/debian-12.docker0000644000000000000000000000036714516424013014501 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT # 20230816 FROM debian:bookworm RUN apt-get update && apt-get install -y git ninja-build patchelf python3-pip python3-venv && rm -rf /var/lib/apt/lists/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/ci/debian-unstable.docker0000644000000000000000000000036714516424013016074 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20230816 FROM debian:unstable RUN apt-get update && apt-get install -y git ninja-build patchelf python3-pip python3-venv && rm -rf /var/lib/apt/lists/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/ci/fedora-37.docker0000644000000000000000000000034314516424013014520 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20221203 FROM fedora:37 RUN dnf -y update && dnf -y install python3-devel python3-pip gcc ninja-build git patchelf && dnf clean all ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/ci/manylinux.docker0000644000000000000000000000032114516424013015051 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20221209 FROM quay.io/pypa/manylinux_2_28_x86_64 RUN dnf -y update && dnf -y install ninja-build && dnf clean all ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/ci/miniconda.docker0000644000000000000000000000035114516424013014771 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20221203 FROM continuumio/miniconda3 RUN apt-get update && apt-get install -y gcc ninja-build git patchelf && rm -rf /var/lib/apt/lists/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/ci/opensuse-15.docker0000644000000000000000000000044114516424013015114 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20230816 FROM opensuse/leap:latest RUN zypper --non-interactive install python311 python311-pip python311-devel gcc ninja git patchelf && zypper clean --all && ln -s python3.11 /usr/bin/python3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/codecov.yml0000644000000000000000000000037614516424013013420 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT comment: false coverage: status: project: default: target: auto threshold: 10% patch: default: informational: true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/about.rst0000644000000000000000000000403714516424013014045 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT License ======= ``meson-python`` is distributed under the terms of the `MIT License`__. ``meson-python`` is tightly coupled to the Meson build system, which is distributed under the the terms of the `Apache License 2.0`__. __ https://github.com/mesonbuild/meson-python/blob/main/LICENSE __ https://github.com/mesonbuild/meson/blob/master/COPYING Maintainers =========== The current maintainers of ``meson-python`` are: - `Ralf Gommers `_ - `Daniele Nicolodi `_ - `Henry Schreiner `_ - `Thomas Li `_ Emeritus maintainers: - `Filipe Laíns `_ Funding ======= Ralf Gommers contributes to the development of ``meson-python`` as part of their job at `Quansight`_. Initial creation of ``meson-python`` by Filipe Laíns was also funded by `Quansight`_. .. _Quansight: https://www.quansight.com/ Packages ======== ``meson-python`` packages are distributed via `PyPI`_ as a source distribution and a single pure Python wheel that works across all supported Python versions. Distributors are recommended to fetch release sources from the corresponding tags on the Git repository_ or from source distributions on `PyPI`_. Git tags are PGP-signed with one of the following keys: - |3DCE51D60930EBA47858BA4146F633CBB0EB4BF2|_ Filipe Laíns - |52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5|_ Ralf Gommers .. _repository: https://github.com/mesonbuild/meson-python .. _PyPI: https://pypi.org/project/meson-python/ .. |3DCE51D60930EBA47858BA4146F633CBB0EB4BF2| replace:: ``3DCE51D60930EBA47858BA4146F633CBB0EB4BF2`` .. _3DCE51D60930EBA47858BA4146F633CBB0EB4BF2: https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3dce51d60930eba47858ba4146f633cbb0eb4bf2 .. |52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5| replace:: ``52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5`` .. _52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5: https://github.com/rgommers.gpg ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1698311297.6262498 meson_python-0.15.0/docs/changelog.rst0000644000000000000000000002430714516426202014666 0ustar00.. SPDX-FileCopyrightText: 2021 The meson-python developers .. .. SPDX-License-Identifier: MIT .. Contributors list for the latest release can be generated with git log --format='%aN' $PREV..HEAD | sort -u | awk '$1=$1' RS='' FS='\n' OFS=', ' +++++++++ Changelog +++++++++ 0.15.0 ====== - Enable compression for wheel files. The may result in several times smaller wheels. - Require Meson 1.2.3 or later on Python 3.12 or later. Meson 1.2.3 does not require anymore ``distutils``, allowing to remove the dependency on ``setuptools`` on Python 3.12 or later. - Unconditionally require ``patchelf`` on Linux. The ``patchelf`` package is added to the build dependencies if a suitable ``patchelf`` executable is not find on the ``$PATH``. This avoids cases where ``meson setup`` was run twice during the build process to determine whether ``patchelf`` is required. - Allow to configure the ``meson`` executable to use for the build process through the ``$MESON`` environment variable or the ``meson`` key under ``[tool.meson-python]`` in ``pyproject.toml``. - Fix wheel platform tag generation on FreeBSD. - Extend support to other UNIX-like systems and make the tests pass on FreeBSD. - Fix package name normalization in package metadata and improve package name validation. - Fix ``RPATH`` handling when the build ``RPATH`` points to subdirectories of the build directory. - Fix support for the Python limited C API when compiling for PyPy. - Rename the ``builddir`` config-setting to ``build-dir``. For backwards compatibility, the ``buildir`` config-setting remains supported as an alias. Christoph Reiter, Daniele Nicolodi, Elliott Sales de Andrade, Ralf Gommers, Yue Yang --- 26-10-2023 0.14.0 ====== - Do not run ``meson install`` to build a wheel. This was unnecessary as files are added to the wheel from the build and source directories. This does not affect the handling of ``meson install`` options, which are interpreted by ``meson-python`` itself. - Obey the ``--skip-subprojects`` when specified for the ``meson install`` command. - Implement support for the ``exclude_directories`` and ``exclude_files`` arguments to Meson ``install_subdir()`` function and similar installation functions. This requires Meson version 1.1.0 or later. - Implement support for building wheels targeting the Python limited API. Extension modules targeting the Python limited API can be easily built starting with the upcoming Meson 1.3.0 release. - When ``pyproject.toml`` does not contain a ``version`` field and ``version`` is not declared dynamic, raise an error instead of silently using the version declared in ``meson.build``. - Fix the mtime of source files in the sdist tarball. - Add ``objc`` and ``objcpp`` compilers to the cross file generated when the ``$ARCHFLAGS`` is set. - Extensive documentation improvements. Charles Brunet, Daniele Nicolodi, Henry Schreiner, Michał Górny, Ralf Gommers --- 05-09-2023 0.13.2 ====== - Fix system name in cross file generated when using ``$ARCHFLAGS``. - Fix handling of ``null`` Meson install tags. Charles Brunet, Daniele Nicolodi --- 22-06-2023. 0.13.1 ====== - Fix regression in cross-compilation via ``$ARCHFLAGS`` on macOS where the cross file was written in the build directory before it was created, resulting in an error. - Do not require setting ``$_PYTHON_HOST_PLATFORM`` when cross-compiling via ``$ARCHFLAGS`` on macOS. - Add the ``--quiet`` option when invoking ``meson install``. The installation paths are a detail of the ``meson-python`` implementation and are generally not interesting for the user. - Fix terminal logging when overriding the current line when listing files added to the wheel. - Improve the error message emitted when a package split between the ``purelib`` and ``platlib`` wheel locations is detected. Daniele Nicolodi, Ralf Gommers --- 28-04-2023. 0.13.0 ====== - Add support for editable installs. - Adjust the default build options passed to ``meson setup``. - Make sure that the directory where the wheel or sdist build artifacts are created exists. Fixes building with PDM. - Fix the specification of the C++ compiler for cross-compilation with ``$ARCHFLAGS`` on macOS. - Pass the ``--reconfigure`` option to ``meson setup`` if and only if the specified build directory exists and is a valid Meson build directory. - Pass the ``--no-rebuild`` option to ``meson install``. - Allow to select the files to be included in the wheel via Meson install tags passing the ``--tags`` option to ``meson install`` via ``pyproject.toml`` or config settings. - Do not use the ``meson compile`` indirection to build the project, except on Windows, where it is required to setup the Visual Studio environment. - Do not add ``ninja`` to the build dependencies if ``$NINJA`` is set but it does not point to a ``ninja`` executable with the required minimum version. - Verify at run time that Meson satisfies the minimum required version. - Place native and cross files in the build directory instead of in the source directory. - Drop the ``typing-extensions`` package dependency. - Add dependency on ``setuptools`` on Python 3.12 and later. This fixes build error due to Meson depending on the ``distutils`` standard library module removed in Python 3.12. - Bump the required ``pyproject-metadata`` version to 0.7.1. - Allows some more cross-compilation setups by not checking extension modules filename suffixes against the suffixes accepted by the current interpreter. - Raise an error when a file that would be installed by Meson cannot be mapped to a wheel location. - Raise an error when a package is split between ``platlib`` and ``purelib``. - Do not generate a warning when ``pyproject.toml`` does not contain a ``project`` section and Python package metadata is derived from ``meson.build``. - Improve reporting of ``pyproject.toml`` validation errors. - Fix validation of tool specific options in ``pyproject.toml``. In particular, allows to specify an incomplete set of options in the ``tool.meson-python.args`` table. Daniele Nicolodi, Doron Behar, Eli Schwartz, Filipe Laíns, Lars Pastewka, Luigi Giugliano, Matthias Köppe, Peter Urban, Ralf Gommers, Stefan van der Walt, Thomas Li --- 18-04-2023. 0.12.1 ====== - Fix regression where the ``$MACOSX_DEPLOYMENT_TARGET`` environment variable was accidentally renamed to ``$MACOS_DEPLOYMENT_TARGET``. Filipe Laíns, Stefan van der Walt --- 17-02-2023. 0.12.0 ====== - Require the ``typing_extensions`` package for Python < 3.10 rather than for Python < 3.8 only. - Emit an error message and raise ``SystemExit`` on expected errors. - Revise error messages for consistency. - Support setuptools-style macOS cross compilation via ``$ARCHFLAGS``. - Allow to overwrite macOS platform tag via ``$_PYTHON_HOST_PLATFORM``. - Include an hint with the most similar known option names in the error message emitted when an unknown config setting is encountered. Daniele Nicolodi, Filipe Laíns, Henry Schreiner, Matthias Köppe, Thomas A Caswell --- 22-12-2022. 0.11.0 ====== - Project moved to the ``mesonbuild`` organization. - Determine wheel tags by introspecting the Python interpreter. - Allow users to pass options directly to Meson via the ``dist``, ``setup``, ``compile``, and ``install`` entries in the ``tools.meson-python.args`` table in ``pyproject.toml``, or via the ``dist-args``, ``setup-args``, ``compile-args``, and ``install-args`` config settings. - Use the system ``ninja`` if possible. Return ``ninja`` as a build dependency otherwise. - Include files generated by ``mesonadd_dist_script`` in the sdist. - Use ``tomllib`` on Python 3.11 or later. - Drop the ``wheel`` package dependency. - Fix bug where the ``entry_points.txt`` file was not generated. - Fix bug where Cygwin Python extensions were not being noticed. Ben Greiner, Daniele Nicolodi, Filipe Laíns, Henry Schreiner, Matthias Köppe, Ralf Gommers, Sam Thursfield, Thomas Li --- 21-11-2022. 0.10.0 ====== - Ignore the minor version on macOS 11 or later, to match the behavior of ``pypa/packaging``. Filipe Laíns, Ralf Gommers --- 05-10-2022. 0.9.0 ===== - More fixes on ABI tag detection. - Fix incorrect tag on 32-bit Python running on a x86_64 host. - Fix sdist permissions. - Fix incorrect PyPy tags. - Fix ``install_subdirs`` not being included in wheels. - Take ``MACOSX_DEPLOYMENT_TARGET`` into account for the platform tag. - Don't set the rpath on binaries if unneeded. Eli Schwartz, Filipe Laíns, Matthias Köppe, Peyton Murray, Ralf Gommers, Thomas Kluyver, Thomas Li --- 29-09-2022. 0.8.1 ===== - Fix ``UnboundLocalError`` in tag detection code. Filipe Laíns, Ralf Gommers --- 28-07-2022. 0.8.0 ===== - Fix sometimes the incorrect ABI tags being generated. - Add workaround for macOS 11 and 12 installations that are missing a minor version in the platform string. Filipe Laíns --- 26-07-2022. 0.7.0 ===== - Fix the wrong Python and ABI tags being generated in Meson 0.63.0. - Fix project license not being included in the project metadata. Filipe Laíns, Ralf Gommers --- 22-07-2022. 0.6.0 ===== - Project re-licensed to MIT. - Error out when running in an unsupported interpreter. - Fix slightly broken Debian heuristics. - Update ``pep621`` dependency to ``pyproject-metadata``. Filipe Laíns, Ralf Gommers, Thomas A Caswell --- 21-06-2022. 0.5.0 ===== - Improvements in dependency detections. - Include uncommited changes in sdists. Filipe Laíns --- 26-05-2022. 0.4.0 ===== - Set sane default arguments for release builds. Filipe Laíns --- 06-05-2022. 0.3.0 ===== - Initial cross-platform support. - Bundling libraries is still only supported on Linux. - Add initial documentation. - The build directory is now located in the project source. Filipe Laíns, Rafael Silva --- 23-03-2022. 0.2.1 ===== - Fix getting the project version dynamically from Meson. Filipe Laíns --- 26-02-2022. 0.2.0 ===== - Select the correct ABI and Python tags. - Force Meson to use the correct Python executable. - Replace auditwheel with in-house vendoring mechanism. Filipe Laíns --- 24-01-2022. 0.1.2 ===== - Fix auditwheel not being run. Filipe Laíns --- 12-11-2021. 0.1.1 ===== - Fix minor compatibility issue with Python < 3.9. Filipe Laíns --- 28-10-2021. 0.1.0 ===== - Initial release. Filipe Laíns --- 28-10-2021. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/conf.py0000644000000000000000000000561014516424013013476 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. import os import sys sys.path.insert(0, os.path.abspath('..')) import mesonpy # -- Project information ----------------------------------------------------- project = 'meson-python' copyright = '2021, The meson-python developers' # The short X.Y version version = mesonpy.__version__ # The full version, including alpha/beta/rc tags release = mesonpy.__version__ # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.todo', 'sphinx_copybutton', 'sphinx_design', 'sphinxext.opengraph', 'sphinx.ext.intersphinx', ] try: import sphinxcontrib.spelling extensions.append('sphinxcontrib.spelling') spelling_show_suggestions = True spelling_warning = True except ImportError: pass # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = [] default_role = 'any' todo_include_todos = True intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'furo' html_title = f'meson-python {version}' html_static_path = ['static'] html_css_files = [ 'css/contributors.css', ] html_theme_options = { 'light_css_variables': { 'font-stack': ( 'system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,' 'Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji' ), }, } # Open Graph ogp_site_url = 'https://meson-python.readthedocs.io' ogp_site_name = 'meson-python documentation' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named 'default.css' will overwrite the builtin 'default.css'. # html_static_path = ['_static'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/contributing/commit-format.rst0000644000000000000000000000061314516424013020214 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _contributing-commit-format: ************* Commit format ************* .. todo:: - Explain is the same as Numpy and SciPy - List valid prefixes - Speak a bit about message clarity - Speak a bit about splitting commits into logical changes - Mention we require a linear history ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/contributing/documentation.rst0000644000000000000000000000170014516424013020305 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _contributing-documentation: ************* Documentation ************* Our documentation is built on sphinx_, is written using reStructuredText_, and follows the Diátaxis_ framework. To automatically re-build the documentation and serve it on an web server, you can pass the ``serve`` argument to the ``docs`` nox_ task. .. code-block:: console $ nox -s docs -- serve When using this argument, the task will watch the documentation source files, and every time you edit something, it will automatically re-build the documentation and make it available on the provided web server. .. todo:: Elaborate more with tips on how to write. .. _sphinx: https://www.sphinx-doc.org .. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html .. _Diátaxis: https://diataxis.fr/ .. _nox: https://github.com/wntrblm/nox ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/contributing/getting-started.rst0000644000000000000000000000036614516424013020550 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _contributing-getting-started: *************** Getting started *************** .. todo:: - Introduction to the development workflow. - ? ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/contributing/index.rst0000644000000000000000000000025414516424013016546 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT Development =========== .. toctree:: documentation release-process ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/contributing/release-process.rst0000644000000000000000000000346614516424013020543 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _contributing-release-process: *************** Release Process *************** All releases are PGP signed with one of the keys listed in the `installation page`_. Before releasing please make sure your PGP key is listed there, and preferably signed by one of the other key holders. If your key is not signed by one of the other key holders, please make sure the PR that added your key to the :ref:`security` page was approved by at least one other maintainer. After that is done, you may release the project by following these steps: #. Release to the Git repository on GitHub: #. Create the release commit #. Bump the versions in ``meson.build`` and ``mesonpy/__init__.py``. #. Create ``CHANGELOG.rst`` section for the new release and fill it. #. The commit message should read: ``REL: set version to X.Y.Z`` #. Create a GPG-signed tag for the release: .. code-block:: console $ git tag -s X.Y.Z The tag title should follow the ``meson-python X.Y.Z`` format, and the tag body should be a plain text version of the change-log for the current release. #. Push the commit and tag to the repository: .. code-block:: console $ git push $ git push --tags #. Release to `PyPI `_ #. Build the Python artifacts: .. code-block:: console $ python -m build #. Push the artifacts to PyPI: .. code-block:: console $ twine upload dist/* There is no need to GPG-sign the artifacts: PyPI no longer supports uploading GPG signatures. If you have any questions, please look at previous releases and/or ping the other maintainers. .. _installation page: installation ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/contributing/test-suite.rst0000644000000000000000000000047514516424013017552 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _contributing-test-suite: ********** Test suite ********** .. todo:: - Introduce nox - Explain our most relevant pytest fixtures (``package_*``, ``sdist_*``, ``wheel_*``, ``editable_*``, ``venv``, etc.) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/examples/spam/meson.build0000644000000000000000000000142714516424013017121 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('spam', 'c', version: '1.0.0') py = import('python').find_installation() # Specify directories to be included - usually this is where your header files live. # Note that specifying the path to Python.h is not necessary with meson-python. includes = include_directories('src') srcs = [ 'src/spammodule.c', ] # If some files (such as .py files) need to be copied to site-packages, # this is where they get specified. Files get copied to # /site-packages/ py.install_sources( 'src/__init__.py', subdir: 'spam', pure: false, ) py.extension_module( '_spam', srcs, install: true, subdir: 'spam', include_directories: includes, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/examples/spam/pyproject.toml0000644000000000000000000000043714516424013017673 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] requires = [ "meson-python", ] build-backend = "mesonpy" [project] name = "spam" description = "Example C extension for Python" version = "0.0.1" requires-python = ">=3.8.0" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/examples/spam/src/__init__.py0000644000000000000000000000020214516424013017645 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from ._spam import add # noqa: F401 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/examples/spam/src/spammodule.c0000644000000000000000000000116514516424013020057 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #define PY_SSIZE_T_CLEAN #include static PyObject * add(PyObject *self, PyObject *args) { int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) return NULL; return PyLong_FromLong(a + b); } static PyMethodDef methods[] = { {"add", add, METH_VARARGS, "Add two integers."}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef spammodule = { PyModuleDef_HEAD_INIT, "spam", NULL, -1, methods }; PyMODINIT_FUNC PyInit__spam(void) { return PyModule_Create(&spammodule); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/explanations/default-options.rst0000644000000000000000000000777714516424013020573 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _explanations-default-options: ********************* Default build options ********************* Meson offers many `built-in options`__ to control how the project is built and installed. In the vast majority of cases those have good defaults. There are however a few options that ``meson-python`` overrides with its own defaults to adjust the build process to the task of building Python wheels. The default options specified by ``meson-python`` are overridden by package specific options specified in ``pyproject.toml`` and by options provided by the user at build time via the Python build front-end. Refer to the :ref:`how-to-guides-meson-args` guide for details. The options used to build the project are summarized in the *User defined options* section of the output of the ``meson setup`` stage of the build, for example when running ``python -m build -w``. This will look something like: __ https://mesonbuild.com/Builtin-options.html .. code-block:: text User defined options Native files: $builddir/meson-python-native-file.ini buildtype : release b_ndebug : if-release b_vscrt : md where the path to the build directory has been replaced with ``$builddir`` for clarity. The options that ``meson-python`` specifies by default are: .. option:: native-file=$builddir/meson-python-native-file.ini ``meson-python`` uses a native file to point Meson at the ``python`` interpreter that the build must target. This is the Python interpreter that is used to run the Python build front-end. Meson would otherwise look for the first Python interpreter on the ``$PATH``, which may not be the same. Additional ``--native-file`` options can be passed to ``meson setup`` if further adjustments to the native environment need to be made. Meson will merge the contents of all machine files. To ensure everything works as expected, the ``meson-python`` native file is last in the command line, overriding the ``python`` binary path that may have been specified in user supplied native files. .. option:: buildtype=release The Meson default is to produce a debug build with binaries compiled with debug symbols and, when compiling with MSVC, linking to the Visual Studio debug runtime, see below. The main purpose of ``meson-python`` is to build release artifacts, therefore a more appropriate `build type`__ is selected. A release build is compiled without debug symbols and with compiler optimizations. Refer to the `Meson documentation`__ for more details. __ https://mesonbuild.com/Builtin-options.html#details-for-buildtype __ https://mesonbuild.com/Builtin-options.html#core-options .. option:: b_ndebug=if-release For reasons related to backward compatibility, Meson does not disable assertions for release builds. For most users this is a surprising and undesired behavior. This option instructs Meson to pass the ``-DNDEBUG`` option to the compilers, unless the build type is set to something else than release. .. option:: b_vscrt=md With the default options, when compiling a debug build, Meson instructs the MSVC compiler to use the debug version of the Visual Studio runtime library. This causes the MSVC linker to look for the debug build of all the linked DLLs. The Python distribution for Windows does not contain a debug version of the Python DLL and linking fails. These linking failures are surprising and hard to diagnose. To avoid this issue when users explicitly asks for a debug build, ``meson-python`` sets this options to instruct Meson to compile with the release version of the Visual Studio runtime. For more details, refer to the `Meson documentation`__ and to the `Visual Studio documentation`__ . This option is ignored when other compilers are used. __ https://mesonbuild.com/Builtin-options.html#base-options __ https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=msvc-170 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/explanations/design-old.rst0000644000000000000000000000726114516424013017467 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT :orphan: .. _explanations-design-old: ******************************* How does ``meson-python`` work? ******************************* .. admonition:: Old documentation :class: attention You are looking at the old documentation. We are currently in the process of refactoring the whole documentation and this page was part of the old version. While it still contains lots of relevant information, it is not necessarily in the format we ultimately want to present, and is not well integrated with the other parts of the documentation. How does it work? ================= We implement the Python build system hooks, enabling any standards compliant Python tool (pip_, `pypa/build`_, etc.) to build and install the project. ``meson-python`` will build a Python sdist (source distribution) or wheel (binary distribution) from Meson_ project. Source distribution (sdist) --------------------------- The source distribution is based on ``meson dist``, so make sure all your files are included there. In git projects, Meson_ will not include files that are not checked into git, keep that in mind when developing. By default, all files under version control will be included in the sdist. In order to exclude files, use ``export-ignore`` or ``export-subst`` attributes in ``.gitattributes`` (see the ``git-archive`` documentation for details; ``meson dist`` uses ``git-archive`` under the hood). Local (uncommitted) changes to files that are under version control will be included. This is often needed when applying patches, e.g. for build issues found during packaging, to work around test failures, to amend the license for vendored components in wheels, etc. Binary distribution (wheels) ---------------------------- The binary distribution is built by running Meson_ and introspecting the build and trying to map the files to their correct location. Due to some limitations and/or bugs in Meson_, we might not be able to map some of the files with certainty. In these cases, we will take the safest approach and warn the user. In some cases, we might need to resort to heuristics to perform the mapping, similarly, the user will be warned. These warnings are not necessarily a reason for concern, they are there to help identifying issues. In these cases, we recommend that you check if the files in question were indeed mapped to the expected place, and open a bug report if they weren't. If the project itself includes shared libraries that are needed by other files, those libraries will be included in the wheel, and native files will have their library search path extended to include the directory where the libraries are placed. If the project depends on external shared libraries, those libraries will not be included in the wheel. This can be handled in several ways by the package developer using ``meson-python``: 1. Finding or creating a suitable Python package that provides those shared libraries and can be added to ``dependencies`` in ``pyproject.toml``. 2. Vendoring those libraries into the wheel. Currently ``meson-python`` does not provide an OS-agnostic way of doing that; on Linux ``auditwheel`` can be used, and on macOS ``delocate``. Or, the package developer can copy the shared libraries into the source tree and patch ``meson.build`` files to include them. 3. Documenting that the dependency is assumed to already be installed on the end user's system, and letting the end user install it themselves (e.g., through their Linux distro package manager). .. _pip: https://github.com/pypa/pip .. _pypa/build: https://github.com/pypa/build .. _Meson: https://github.com/mesonbuild/meson ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/explanations/design.rst0000644000000000000000000000105714516424013016710 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _explanations-design: ******************************* How does ``meson-python`` work? ******************************* .. todo:: - Explain how ``meson-python`` maps files to the wheel - Link to :ref:`tutorials-executable` in the relevant section - Explain why we don't support ``install_data`` - Link to the relevant :ref:`reference-limitations` section - ? You can find the old documentation :ref:`here `. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/explanations/editable-installs.rst0000644000000000000000000000073214516424013021036 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _explanations-editable-installs: ****************************** How do editable installs work? ****************************** .. todo:: - Explain how the custom finder works - Explain what is the purpose of the ``_MESONPY_EDITABLE_SKIP`` environment variable - Warn that the approach described is purely informational, and should not be relied on ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/explanations/internal-dependencies.rst0000644000000000000000000000155114516424013021676 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _explanations-internal-dependencies: *************************************** How do we handle internal dependencies? *************************************** .. todo:: - Explain why bundle internal dependencies - Explain how we bundle internal dependencies - Explain how we patch the ``RPATH`` - Mention our limitation regarding executables with internal dependencies - Link to the relevant :ref:`reference-limitations` section - Explain how to work around it (using a static library) - Mention how the ``pyproject.toml`` settings can be used to only enable the workaround on meson-python builds (by adding a custom Meson option and enabling it on meson-python builds) - Link to :ref:`reference-pyproject-settings` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/how-to-guides/build-directory.rst0000644000000000000000000000126614516424013020530 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-build-directory: ******************************* Use a permanent build directory ******************************* .. todo:: - Explain why you'd want to use the ``build-dir`` option - Mention it works properly when using ``--cross-file`` (eg. https://github.com/scipy/scipy/blob/1c836efe5ff37ffa4490756269b060a464690e62/.github/workflows/wheels.yml#L180-L188) - Explain how ``build-dir`` works - Warn that user-configured build directories are "use at your own risk" - Warn that ``meson-python`` version mismatches in the build directory can cause trouble ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/how-to-guides/config-settings.rst0000644000000000000000000000445714516424013020537 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-config-settings: ************************* Use build config settings ************************* Build config settings are settings you can pass to ``meson-python`` when building your project. They can be use to customize the build in some aspect. Several Python build front-ends exist, with different ways to pass configuration settings to the build back-end. The most popular are `pypa/build`_, which uses the ``-C`` command line option, and `pip`_, which uses the ``--config-settings`` option. For example: .. _pypa/build: https://github.com/pypa/build .. _pip: https://github.com/pypa/pip .. tab-set:: .. tab-item:: pypa/buid :sync: key_pypa_build .. code-block:: console $ python -m build \ -Csetup-args="-Doption=true" \ -Csetup-args="-Dvalue=1" \ -Ccompile-args="-j6" .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel . \ --config-settings=setup-args="-Doption=disable" \ --config-settings=compile-args="-j6" This examples use the ``python -m pip wheel`` command to build a Python wheel that can be later installed or distributed. To build a package and immediately install it, just replace ``wheel`` with ``install``. See the :ref:`how-to-guides-meson-args` guide for more examples. Refer to the `pypa/build documentation`_ or to the `pip documentation`_ for more information. .. _pypa/build documentation: https://pypa-build.readthedocs.io/en/stable/ .. _pip documentation: https://pip.pypa.io/ .. admonition:: Passing multiple settings :class: caution Please note that, while ``pypa/build`` concatenates arguments for the same key passed to the ``-C`` option, ``pip`` up to version 23.0.1 does not offer any way to set a build config setting to a list of strings: later values for the same key passed to ``--config-settings`` override earlier ones. This effectively limits the number of options that can be passed to each command invoked in the build process to one. This limitation is tracked in `pip issue #11681`_. This limitation should be removed in the next version of pip. .. _pip issue #11681: https://github.com/pypa/pip/issues/11681 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/how-to-guides/debug-builds.rst0000644000000000000000000000423014516424013017767 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-debug-builds: ****************** Using debug builds ****************** For development work on native code in your Python package, you may want to use a debug build. To do so, we need to pass the ``-Dbuildtype=debug`` option, which is equivalent to ``-Ddebug=true -Doptimization=0``, to ``meson setup``. In addition, it is likely most useful to set up an editable build with a fixed build directory. That way, the shared libraries in the installed debug build will contain correct paths, rather than paths pointing to a temporary build directory which ``meson-python`` will otherwise use. IDEs and other tools will then be able to show correct file locations and line numbers during debugging. We can do all that with the following ``pip`` invocation: .. code-block:: console $ pip install -e . --no-build-isolation \ -Csetup-args=-Dbuildtype=debug \ -Cbuild-dir=build-dbg This debug build of your package will work with either a regular or debug build of your Python interpreter. A debug Python interpreter isn't necessary, but may be useful. It can be built from source, or you may be able to get it from your package manager of choice (typically under a package name like ``python-dbg``). Note that using a debug Python interpreter does not yield a debug build of your own package - you must use ``-Dbuildtype=debug`` or an equivalent flag for that. .. warning:: Inside a Conda environment, environment variables like ``CFLAGS`` and ``CXXFLAGS`` are usually set when the environment is activated. These environment variables contain optimization flags like ``-O2``, which will override the optimization level implied by ``-Dbuildtype=debug``. In order to avoid this, unset these variables: .. code-block:: console $ unset CFLAGS $ unset CXXFLAGS Finally, note changing the buildtype from its default value of ``release`` to ``debug`` will also cause ``meson-python`` to enable (or better, not disable) assertions by not defining the ``NDEBUG`` macro (see ``b_ndebug`` under :ref:`explanations-default-options`). ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/how-to-guides/editable-installs.rst0000644000000000000000000001232614516424013021026 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-editable-installs: ***************** Editable installs ***************** Editable installs are a Python package installation mode designed to facilitate package development. When a package is installed in editable mode, edits to the project source code become effective without the need of a new installation step. Editable installs are a build backend independent formalization__ of the *development mode* introduced by setuptools__. __ https://peps.python.org/pep-0660/ __ https://setuptools.pypa.io/en/latest/userguide/development_mode.html While most Python build backends apply development mode or editable installs to the pure Python components, ``meson-python`` extends editable installs to package components that require a compilation step such as extension modules. To install a package in editable mode, pass the ``--editable`` or ``-e`` option to ``pip install``. The editable installation mode implies that the source code of the project being installed is available in a local directory. To install the project in the current directory in editable mode install the project's build dependencies in your development environment and run .. code-block:: console $ python -m pip install --no-build-isolation --editable . This will install a stub in the Python site packages directory that loads the package content from the sources and build directory. The same stub is responsible to rebuild the compiled parts of the package when the package is imported the first time in a given Python interpreter instance. Because of the very fast partial rebuilds allowed by Meson and ``ninja``, the rebuild has an almost negligible impact on the import times. Please note that some kind of changes, such as the addition or modification of `entry points`__, or the addition of new dependencies, and generally all changes involving package metadata, require a new installation step to become effective. __ https://packaging.python.org/en/latest/specifications/entry-points/ An editable install exposes at least all the files that would be available in a regular installation. However, depending on the file and directory organization in your project, it might also expose files that would not be normally available. Build dependencies ------------------ Because packages installed in editable mode are rebuilt on import, all build dependencies need to available at execution time in the development environment. By default, pip builds packages in a isolated environment where build dependencies are installed without affecting the user environment. Packages installed in editable mode using build isolation will fail to rebuild when imported, unless build dependencies are also installed in the development environment. Furthermore, when build using build isolation, a package that depends on headers or other resources provided by its build dependencies, would resolve the path to these in the isolated build environment. The isolated build environment is deleted after the build is completed, resulting in failures when the package in rebuild on import. For these reasons, when installing packages in editable mode, it is recommended to disable build isolation passing the ``--no-build-isolation`` argument to pip. At the time of writing, pip does not offer a command to install a the build dependencies for a package. The build dependencies requirements can be obtained inspecting ``pyproject.toml`` for the package to be installed. These include at least the ``meson-python`` Python package, and the ``meson`` and ``ninja`` Python packages, if the respective commands are not provided by the system, or if they are not the required version: .. code-block:: console $ python -m pip install meson-python meson ninja Build directory --------------- Because the compiled components of the package are loaded directly from the build directory, the build directory needs to be available alongside the source directory at execution time. When building a package in editable mode, ``meson-python`` uses a build directory named as the wheel ABI tag associated to the interpreter for which the package is being build. The build directory is placed in a directory named ``build`` inside the source tree. For example, an editable installation for CPython 3.11 will be associated to a ``build/cp311/`` build directory. This directory structure allows to install the same project in editable mode for multiple interpreters with different ABIs. An alternative build directory can be specified using the :option:`build-dir` config setting. .. _how-to-guides-editable-installs-verbose: Verbose mode ------------ Because editable installation are mostly a package development aid, it might be often useful to be able to inspect the compilation log. Setting the :envvar:`MESONPY_EDITABLE_VERBOSE` environment variable will result in the output of the build process to be emitted when a package is rebuilt on import. To enable this verbose mode permanently for a package, the :option:`editable-verbose` config setting can be set to a non-null value when installing the package: .. code-block:: console $ python -m pip install --no-build-isolation --config-settings=editable-verbose=true --editable . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/how-to-guides/first-project.rst0000644000000000000000000000447114516424013020223 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-first-project: ************* First project ************* .. admonition:: Advanced guide :class: caution This guide assumes you are already familiarized with Python packaging! If you aren't, we recommend you check our :ref:`tutorial-introduction` tutorial instead. ``meson-python`` builds on top of an existing Meson_ project, so you'll need the top-level ``meson.build`` for a Meson_ project next to your ``pyproject.toml``. You can check our `example project`_ or the projects in the :ref:`projects-using-meson-python` page for examples. .. admonition:: Getting started with Meson_ :class: seealso If you are not familiar with Meson_, we would recommend checking out their tutorial_. Specifying the backend ====================== Our build backend is called ``mesonpy``, and that's what you should specify in the ``build-system.build-backend`` key of ``pyproject-toml``. You should add ``meson-python``, and all other build dependencies (eg. Cython_) needed by your Meson_ project, in the ``build-system.requires`` key. Example ------- .. code-block:: toml :caption: pyproject.toml [build-system] build-backend = 'mesonpy' requires = ['meson-python', 'cython'] Specifying the project metadata =============================== We use the standard metadata format in the ``project`` section of ``pyproject.toml``. Please refer to the `relevant PyPA documentation page`_ for a full specification. Example ======= .. code-block:: toml :caption: pyproject.toml [build-system] build-backend = 'mesonpy' requires = ['meson-python', 'cython'] [project] name = 'example-package' version = '1.0.0' description = 'Our example package using meson-python!' readme = 'README.md' requires-python = '>=3.8' license = {file = 'LICENSE.txt'} authors = [ {name = 'Bowsette Koopa', email = 'bowsette@example.com'}, ] .. _Cython: https://github.com/cython/cython .. _Meson: https://mesonbuild.com/ .. _relevant PyPA documentation page: https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ .. _example project: https://github.com/mesonbuild/meson-python/tree/main/docs/examples/spam .. _tutorial: https://mesonbuild.com/Tutorial.html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/how-to-guides/meson-args.rst0000644000000000000000000001467214516424013017507 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-meson-args: ************************** Passing arguments to Meson ************************** ``meson-python`` invokes the ``meson setup``, ``ninja``, and ``meson install`` commands to build the files that will be included in the Python wheel, and ``meson dist`` to collect the files that will be included in the Python sdist. Arguments can be passed to these commands to modify their behavior. Refer to the `Meson documentation`_ and to the `ninja documentation`_ for details. .. _Meson documentation: https://mesonbuild.com/Commands.html .. _ninja documentation: https://ninja-build.org/manual.html#_running_ninja Command line arguments for ``meson`` and ``ninja`` can be specified via tool specific settings in ``pyproject.toml`` as lists of strings for the ``setup``, ``compile``, ``install``, and ``dist`` keys in the ``tool.meson-python.args`` table. For example: .. code-block:: toml [tool.meson-python.args] setup = ['-Doption=false', '-Dfeature=enabled', '-Dvalue=42'] compile = ['-j4'] install = ['--tags=bindings'] dist = ['--include-subprojects'] Or can be specified via configuration settings passed by the Python build front-end as ``setup-args``, ``compile-args``, ``install-args``, and ``dist-args`` :ref:`config settings `. Configuration settings specified via the Python build front-end have precedence over, and can be used to override, the ones specified in ``pyproject.toml``. ``meson-python`` overrides some of the default Meson options with :ref:`settings ` more appropriate for building a Python wheel. User options specified via ``pyproject.toml`` or via Python build front-end config settings override the ``meson-python`` defaults. When building on Windows, ``meson-python`` invokes the ``ninja`` command via the ``meson compile`` wrapper. When the GCC or the LLVM compilers are not found on the ``$PATH``, this activates the Visual Studio environment and allows ``ninja`` to use the MSVC compilers. To activate the Visual Studio environment unconditionally, pass the ``--vsenv`` option to ``meson setup``, see this :ref:`example `. When using the ``meson compile`` wrapper, the user supplied options for the compilation command are passed via the ``--ninja-args`` option. This ensures that the behaviour is independent of how the build is initiated. Refer to the `Meson documentation`__ for more details. __ https://mesonbuild.com/Commands.html#backend-specific-arguments Examples ======== Set the default libraries to static ----------------------------------- Set the default library type to static when building a binary wheel. To set this option permanently in the project's ``pyproject.toml``: .. code-block:: toml [tool.meson-python.args] setup = ['--default-library=static'] To set this option temporarily at build-time: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build -Csetup-args="--default-library=static" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel --config-settings=setup-args="--default-library=static" . Select the build targets to include in the wheel ------------------------------------------------ It is possible to include in the Python wheel only a subset of the installable files using Meson `installation tags`_ via the ``meson install``'s ``--tags`` command line option. When ``--tags`` is specified, only files that have one of the specified the tags are going to be installed. Meson sets predefined tags on some files. Custom installation tags can be set using the ``install_tag`` keyword argument passed to the target definition function. In this example only targets tagged with ``runtime`` or ``python-runtime`` are included in the Python wheel. .. _installation tags: https://mesonbuild.com/Installing.html#installation-tags To set this option permanently in the project's ``pyproject.toml``: .. code-block:: toml [tool.meson-python.args] install = ['--tags=runtime,python-runtime'] To set this option temporarily at build-time: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build -Cinstall-args="--tags=runtime,python-runtime" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel --config-settings=install-args="--tags=runtime,python-runtime" . Set the build optimization level -------------------------------- The default compile optimization level when building a binary wheel is currently set to 2. This can be overwritten by passing the ``-Doptimization`` argument to the ``meson setup`` command. To set this option permanently in the project's ``pyproject.toml``: .. code-block:: toml [tool.meson-python.args] setup = ['-Doptimization=3'] To set this option temporarily at build-time: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build -Csetup-args="-Doptimization=3" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel --config-settings=setup-args="-Doptimization=3" . .. _vsenv-example: Force the use of the MSVC compilers on Windows ---------------------------------------------- The MSVC compilers are not installed in the ``$PATH``. The Visual Studio environment needs to be activated for ``ninja`` to be able to use these compilers. This is taken care of by ``meson compile`` but only when the GCC compilers or the LLVM compilers are not found on the ``$PATH``. Passing the ``--vsenv`` option to ``meson setup`` forces the activation of the Visual Studio environment and generates an error when the activation fails. This option has no effect on other platforms thus, if your project requires to be compiled with MSVC, you can consider to set this option permanently in the project's ``pyproject.toml``: .. code-block:: toml [tool.meson-python.args] setup = ['--vsenv'] To set this option temporarily at build-time: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build -Csetup-args="--vsenv" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel --config-settings=setup-args="--vsenv" . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/index.rst0000644000000000000000000000576014516424013014046 0ustar00.. SPDX-FileCopyrightText: 2022 The meson-python developers .. .. SPDX-License-Identifier: MIT ************ meson-python ************ .. highlights:: ``meson-python`` is a Python build backend built on top of the Meson build-system. It enables you to use Meson for your Python packages. Want to look at examples in real projects? Check out our curated list of ``meson-python`` projects :ref:`here `. Where to start? =============== If you are new to Python packaging, we recommend you check our :ref:`tutorial-introduction` tutorial, which walks you through creating and releasing your first Python package. If you are already familiar with Python packaging, we recommend you check our :ref:`how-to-guides-first-project` guide, which shows you how to quickly setup a ``meson-python`` project. How to reach us? ================ ``meson-python`` is an open source project, so all support is at a best-effort capacity, but we are happy to help where we can. If you have a general question feel free to `start a discussion`_ on Github. If you want to report a bug, request a feature, or propose an improvement, feel free to open an issue on our bugtracker_. .. admonition:: Search first! :class: tip Before starting a discussion, please try searching our bugtracker_ and `discussion page`_ first. .. toctree:: :caption: Tutorials :hidden: tutorials/introduction .. tutorials/entrypoints tutorials/executable .. toctree:: :caption: How to guides :hidden: how-to-guides/first-project how-to-guides/editable-installs how-to-guides/config-settings how-to-guides/meson-args how-to-guides/debug-builds projects-using-meson-python .. how-to-guides/build-directory .. toctree:: :caption: Reference :hidden: reference/config-settings reference/pyproject-settings reference/environment-variables explanations/default-options reference/limitations reference/meson-compatibility .. reference/quirks .. toctree:: :caption: Explanations :hidden: explanations/design explanations/internal-dependencies explanations/editable-installs .. toctree:: :caption: Project :hidden: changelog about contributing/index Source Code Issue Tracker .. _getting started: usage/start.html .. _pip: https://github.com/pypa/pip .. _pypa/build: https://github.com/pypa/build .. _build options page: usage/build-options.html .. _install_data: https://mesonbuild.com/Reference-manual_functions.html#install_data .. _start a discussion: https://github.com/mesonbuild/meson-python/discussions/new/choose .. _bugtracker: https://github.com/mesonbuild/meson-python/issues .. _discussion page: https://github.com/mesonbuild/meson-python/discussions .. _#meson-python: https://discord.com/channels/803025117553754132/1040322863930024057 .. _PyPA Discord: https://discord.gg/pypa .. |install_data| replace:: ``install_data`` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/projects-using-meson-python.rst0000644000000000000000000000261614516424013020346 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _projects-using-meson-python: ******** Examples ******** Here's a curated list of projects using ``meson-python``. .. list-table:: :widths: 20 80 * - `SciPy `_ - Probably the most complex project using Meson and ``meson-python``. It combines `CPython extensions`_ and libraries written in C, C++, Cython_, Fortran_, Pythran_, etc., it targets a wide variety of platforms. * - `scikit-image `_ - Another complex project using ``meson-python``. * - `siphash24 `_ - A very simple project. It demonstrates how Meson makes it trivial to compile a `CPython extension`_ written in `Cython`_ via a simple template engine and link it to a library compiled from a Meson sub-project. Also an example of how to use `cibuildwheel`_ to produce Python wheels for several platforms. .. _CPython extension: https://docs.python.org/3/extending/extending.html .. _CPython extensions: https://docs.python.org/3/extending/extending.html .. _Cython: https://github.com/cython/cython .. _Fortran: https://fortran-lang.org/ .. _Pythran: https://github.com/serge-sans-paille/pythran .. _cibuildwheel: https://github.com/pypa/cibuildwheel ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/reference/config-settings.rst0000644000000000000000000000323214516424013017770 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _reference-config-settings: ********************* Build config settings ********************* This page lists the build configuration settings, that is, the settings you can pass when building the project. Please refer to the :ref:`how-to-guides-config-settings` and :ref:`how-to-guides-meson-args` guides for information on how to use them. .. option:: build-dir By default ``meson-python`` uses a temporary build directory. This settings allows to select the Meson build directory and prevents it to be deleted when ``meson-python`` terminates. If the directory does not exists, it will be created. If the directory exists and contains a valid Meson build directory setup, the project will be reconfigured using ``meson setup --reconfigure``. The same build directory can be used by subsequent invocations of ``meson-python``. This avoids having to rebuild the whole project when testing changes during development. For backward compatibility reasons, the alternative ``builddir`` spelling is also accepted. .. option:: dist-args Extra arguments to be passed to the ``meson dist`` command. .. option:: setup-args Extra arguments to be passed to the ``meson setup`` command. .. option:: compile-args Extra arguments to be passed to the ``ninja`` command. .. option:: install-args Extra arguments to be passed to the ``meson install`` command. .. option:: editable-verbose Enable :ref:`verbose mode ` when building for an :ref:`editable install `. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/reference/environment-variables.rst0000644000000000000000000000707714516424013021212 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _reference-environment-variables: ********************* Environment variables ********************* .. envvar:: ARCHFLAGS This environmental variable is used for supporting architecture cross compilation on macOS in a way compatible with setuptools_. It is ignored on all other platforms. It can be set to ``-arch arm64`` or to ``-arch x86_64`` for compiling for the arm64 and the x86_64 architectures respectively. Setting this environment variable to any other value is not supported. The macOS toolchain allows architecture cross compilation passing the ``-arch`` flat to the compilers. ``meson-python`` inspects the content of this environment variable and synthesizes a Meson `cross build definition file`_ with the appropriate content, and passes it to ``meson setup`` via the ``--cross-file`` option. Support for this environment variable is maintained only for compatibility with existing tools, cibuildwheel_ in particular, and is not the recommended solution for cross compilation. .. _setuptools: https://setuptools.pypa.io/en/latest/setuptools.html .. _cross build definition file: https://mesonbuild.com/Cross-compilation.html .. _cibuildwheel: https://cibuildwheel.readthedocs.io/en/stable/ .. envvar:: FORCE_COLOR Setting this environment variable to any value forces the use of ANSI escape sequences to colorize the ``meson-python``'s console output. Setting both ``NO_COLOR`` and ``FORCE_COLOR`` environment variables is an error. .. envvar:: MACOSX_DEPLOYMENT_TARGET This environment variables is used of specifying the target macOS platform major version to the Xcode development tools. If this environment variable is set, ``meson-python`` will use the specified macOS version for the Python wheel platform tag instead than the macOS version of the build machine. This variable must be set to macOS major versions only: ``10.9`` to ``10.15``, ``11``, ``12``, ``13``, ... Please note that the macOS versioning changed from macOS 11 onward. For macOS 10, the versioning scheme is ``10.$major.$minor``. From macOS 11 onward, it is ``$major.$minor.$bugfix``. Wheel tags and deployment targets are currently designed to specify compatibility only with major version number granularity. Another way of specifying the target macOS platform is to use the ``-mmacosx-version-min`` compile and link flags. However, it is not possible for ``meson-python`` to detect this, and it will not set the Python wheel platform tag accordingly. .. envvar:: MESON Specifies the ``meson`` executable or script to use. It overrides ``tool.meson-python.meson``. See :ref:`reference-pyproject-settings` for more details. .. envvar:: MESONPY_EDITABLE_VERBOSE Setting this environment variable to any value enables directing to the console the messages emitted during project rebuild triggered by imports of editable wheels generated by ``meson-python``. Refer to the :ref:`how-to-guides-editable-installs` guide for more information. .. envvar:: NINJA Specifies the ninja_ executable to use. It can also be used to select ninja_ alternatives like samurai_. .. _ninja: https://ninja-build.org .. _samurai: https://github.com/michaelforney/samurai .. envvar:: NO_COLOR Setting this environment variable to any value disables the use of ANSI terminal escape sequences to colorize ``meson-python``'s console output. Setting both ``NO_COLOR`` and ``FORCE_COLOR`` environment variables is an error. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/reference/limitations.rst0000644000000000000000000000311714516424013017223 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _reference-limitations: *********** Limitations *********** Non-package data files ====================== It is possible to encapsulate arbitrary data files into Python wheels. ``meson-python`` will add to the wheel any data file installed into the Meson's ``{datadir}`` location, for example via Meson's |install_data()|_ function. However, when the resulting wheel is installed, these files are unpacked into a platform-specific location and there is no supported facility to reliably find them at run time. It is recommended to include data files than need to be accessible at run-time inside the package alongside the Python code, and use :mod:`importlib.resources` (or the `importlib-resources`_ backport) to access them. Shared libraries on Windows =========================== On Windows, ``meson-python`` cannot encapsulate shared libraries installed as part of the Meson project into the Python wheel for Python extension modules or executables, in a way suitable for them to be found at run-time. This limitation can be overcome with static linking or using `delvewheel`_ to post-process the Python wheel to bundle the required shared libraries and include the setup code to properly set the library search path. .. _install_data(): https://mesonbuild.com/Reference-manual_functions.html#install_data .. _importlib-resources: https://importlib-resources.readthedocs.io/en/latest/index.html .. _delvewheel: https://github.com/adang1345/delvewheel .. |install_data()| replace:: ``install_data()`` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/reference/meson-compatibility.rst0000644000000000000000000000375514516424013020667 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _meson-compatibility: ******************* Meson compatibility ******************* ``meson-python`` tightly integrates with Meson to produce Python wheels and sdists. Therefore, correct operation depends on functionality implemented by Meson. ``meson-python`` strives to maintain compatibility with as old as possible Meson releases. However, some functionality is available only with more recent Meson versions. .. option:: 0.63.3 Meson is 0.63.3 is the minimum required version. .. option:: 1.1.0 Meson 1.1.0 or later is required to support the ``exclude_files`` and ``exclude_directories`` arguments to Meson ``install_subdir`` and similar installation functions. On older Meson versions, these arguments have no effect. .. option:: 1.2.3 Python 3.12 Meson 1.2.3 and later do not rely anymore on ``distutils`` and is required to support support Python 3.12 and later where the ``distutils`` modules has been removed from the Python standard library. ``meson-python`` depends on this versions of Meson, when installed on Python 3.12, thus packages using ``meson-python`` do not need to add an explicit version requirement. .. option:: 1.3.0 Meson 1.3.0 or later is required for compiling extension modules targeting the Python limited API. Build front-ends by default build packages in an isolated Python environment where build dependencies are installed. Most often, unless a package or its build dependencies declare explicitly a version constraint, this results in the most recent version of the build dependencies to be installed. However, if a package uses functionalities implemented only in combination with a specific Meson version, it is recommended to explicitly declare a version requirement in ``pyproject.toml``. For example: .. code-block:: toml [build-system] build-backend = 'mesonpy' requires = [ 'meson-python', 'meson >= 1.1.0', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/reference/pyproject-settings.rst0000644000000000000000000000377514516424013020556 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _reference-pyproject-settings: *************************** ``pyproject.toml`` settings *************************** This page lists the configuration settings supported by ``meson-python`` in the ``pyproject.toml`` file. Please refer to the :ref:`how-to-guides-meson-args` guide for for information on how to use them and examples. .. option:: tool.meson-python.limited-api A boolean indicating whether the extension modules contained in the Python package target the `Python limited API`__. Extension modules can be compiled for the Python limited API specifying the ``limited_api`` argument to the |extension_module()|__ function in the Meson Python module. When this setting is set to true, the value ``abi3`` is used for the Python wheel filename ABI tag. This setting is automatically reverted to false when the ``-Dpython.allow_limited_api=false`` option is passed to ``meson setup``. .. option:: tool.meson-python.meson A string specifying the ``meson`` executable or script to use. If it is a path to an existing file with a name ending in ``.py``, it will be invoked as a Python script using the same Python interpreter that is used to run ``meson-python`` itself. It can be overrridden by the :envvar:`MESON` environment variable. .. option:: tool.meson-python.args.dist Extra arguments to be passed to the ``meson dist`` command. .. option:: tool.meson-python.args.setup Extra arguments to be passed to the ``meson setup`` command. .. option:: tool.meson-python.args.compile Extra arguments to be passed to the ``ninja`` command. .. option:: tool.meson-python.args.install Extra arguments to be passed to the ``meson install`` command. __ https://docs.python.org/3/c-api/stable.html?highlight=limited%20api#stable-application-binary-interface __ https://mesonbuild.com/Python-module.html#extension_module .. |extension_module()| replace:: ``extension_module()`` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/reference/quirks.rst0000644000000000000000000000153314516424013016205 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _reference-quirks: ****** Quirks ****** .. todo:: - Document requirements on how ``import('python').find_installation()`` is called (see `#233`_) - Document that Meson, and thus meson-python, require MSVC compilers to be found in ``$PATH`` on Windows (see `#224`_) .. _reference-quirks-mixing-purelib-and-platlib: Mixing ``purelib`` and ``platlib`` ================================== .. todo:: - Explain in which cases, and how this can cause issues - Explain how to fix (specifying ``pure`` in the necessary targets) - Present changing ``pure`` globally as an option (depending on the use-case) .. _#233: https://github.com/mesonbuild/meson-python/issues/233 .. _#224: https://github.com/mesonbuild/meson-python/issues/224 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/spelling_wordlist.txt0000644000000000000000000000033014516424013016476 0ustar00auditwheel backend backends backport config CPython Cygwin distro eg executables frontend Github macOS nox Numpy pre pluggy pypa pyproject pytest rpath sdist sdists setuptools todo toml uncommited vendored vendoring ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/spelling_wordlist.txt.license0000644000000000000000000000013414516424013020121 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/static/css/contributors.css0000644000000000000000000000105514516424013017524 0ustar00/* * SPDX-FileCopyrightText: 2023 The meson-python developers * * SPDX-License-Identifier: MIT */ .sphinx-contributors--avatars .sphinx-contributors_contributor__image { border-radius: 50%; max-width: 80px; margin: auto; } .sphinx-contributors--avatars .sphinx-contributors_contributor__username { font-size: 80%; text-align: center; } .sphinx-contributors--avatars .sphinx-contributors_contributor { flex-grow: 1; } .sphinx-contributors--avatars .sphinx-contributors_list { justify-content: flex-start; gap: 10px; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/tutorials/entrypoints.rst0000644000000000000000000000056114516424013017355 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _tutorials-entrypoints: ************ Entry points ************ .. todo:: - Mention what is the purpose of entry points - Give an example of a console entry point - Give an example of a custom entry point - Mention pluggy maybe for an example use-case? ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/tutorials/executable.rst0000644000000000000000000000106414516424013017077 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _tutorials-executable: ********** Executable ********** .. todo:: - Give an example of how to build an executable in Meson - Show where the executable gets mapped to inside a wheel - Link to relevant :ref:`explanations-design` section - Mention the limitation regarding internal dependencies - Link to the relevant :ref:`reference-limitations` section - Link to the :ref:`how-to-guides-executable-with-internal-dependencies` guide ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/docs/tutorials/introduction.rst0000644000000000000000000002277514516424013017513 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _tutorial-introduction: ****************************************************** Introduction to Python packaging with ``meson-python`` ****************************************************** If you are new to Python packaging, don't worry! We will give you a quick introduction to what steps releasing a Python package consists of, and walk you through them to get started. Creating a Meson project ======================== To get started, we need a project to publish. As ``meson-python`` is built on top of Meson_, we will create a really simple Meson project. You may already have a Meson project you wish to publish, in that case, you can simply skip this step. The module ---------- First, we create a simple Python module. We will go for a native module, as that's really where ``meson-python`` shines against other Python build backends. .. code-block:: c :caption: our_first_module.c #include static PyObject* foo(PyObject* self) { return PyUnicode_FromString("bar"); } static PyMethodDef methods[] = { {"foo", (PyCFunction)foo, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "our_first_module", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_our_first_module(void) { return PyModule_Create(&module); } Here, we have a create a small module named ``our_first_module``, which has a function ``foo`` that simply returns ``"bar"``. .. admonition:: Using the C API :class: seealso If you need help writing a native module using Python's C API, we recommend checking out the following resources. - `The official Python C API documentation `_ - `RealPython's "Building a Python C Extension Module" introductory tutorial `_ - `pysheeet's "C Extensions" page `_ - `pysheeet-kr's "Python C API cheatsheet" page `_ The Meson build description --------------------------- Now, we need to create the Meson build description file. This tells Meson what we want it to build, and how to do it. .. code-block:: meson :caption: meson.build project('purelib-and-platlib', 'c') py = import('python').find_installation(pure: false) py.extension_module( 'our_first_module', 'our_first_module.c', install: true, ) Here, we use Meson's `Python module`_ to build our ``our_first_module`` module. We make sure to install it, by passing ``install: true`` to ``extension_module``, as ``meson-python`` will only include in the binary distribution artifacts targets that Meson would install onto system. Having non installed targets allows you to build targets for use within the build, or for tests. Configuring our Python package ============================== Now, we need to tell Python packaging tooling what build backend to use to build our package. We do this by creating a ``build-system`` section in the ``pyproject.toml`` file, which is the file used to configure Python packaging tooling. Inside the ``build-system`` section, we need to define two keys, ``build-backend`` and ``requires``. ``build-backend`` defines which build backend should be used for the project - set it to ``'mesonpy'`` to use ``meson-python``. ``requires`` lets us specify which packages need to be installed for the build process, it should include ``meson-python`` and any other dependencies you might need (e.g., ``Cython``). .. code-block:: toml :caption: pyproject.toml [build-system] build-backend = 'mesonpy' requires = ['meson-python'] After we specify which backend to use, we'll want to define the package metadata. This is done in the ``project`` section, and the format is pretty self-explanatory: .. code-block:: toml :caption: pyproject.toml ... [project] name = 'our-first-project' version = '0.0.1' description = 'Our first Python project, using meson-python!' readme = 'README.md' requires-python = '>=3.8' license = {file = 'LICENSE.txt'} authors = [ {name = 'Bowsette Koopa', email = 'bowsette@example.com'}, ] .. admonition:: Declaring project metadata :class: seealso Our example doesn't make use of all the fields available in the ``[project]`` section. Check out the `PyPA documentation on project metadata`_ for more examples and details. Testing the project ------------------- Now we should have a valid Python project, so let's test it. We will install it with pip_: .. code-block:: console $ pip install . $ pip list ... our-first-project 0.0.1 ... After this, we should be able to import and try out our module. .. code-block:: console $ python >>> import our_first_module >>> our_first_module.foo() 'bar' Creating your first release =========================== Now that we have a valid Python project, we can release it. To release the project we first need to generate the distribution artifacts, these are files in a standardized format that Python package installers understand. There are two kind of artifacts, `source distributions`_, which are commonly referred to as *sdists*, and `binary distributions`_, which use a custom format named *wheel*, so they're generally referred to as *wheels*. What are the roles of sdists and wheels? ---------------------------------------- As you might have figured out by the name, sdists contain the source code of the project, and wheels contain a compiled [#pure-wheels]_ version of the project, ready to be copied to the file system. If your project uses Python extension modules, your wheels will be specific to both the platform and the Python version [#stable-abi]_. While distributing wheels is not mandatory, they make the user experience much nicer. Unless you have any reason not to, we highly recommend you distribute wheels for at least the most common systems. When wheels are not available for a system, the project can still be installed, be it needs to be build from the sdist, which involves fetching all the build dependencies and going through the likely expensive build process. .. [#pure-wheels] Projects that don't have any compiled code will have a platform-independent -- *pure* -- wheel. .. [#stable-abi] Unless you are using the `stable ABI`_, which limits you to a subset of the Python C API, with the trade-off that your native code will be compatible with multiple Python versions. Building the project -------------------- Before continuing, ensure you have committed the three files we created so far to your Git repository - ``meson-python`` will only take into account the files that Git knows about. To generate the distribution artifacts we will use the `pypa/build`_ tool. It will create a temporary virtual environment, install all the required build dependencies, and ask ``meson-python`` to build the artifacts. .. code-block:: console $ pip install build $ python -m build If the build succeeded, you'll have the binary artifacts in the ``dist`` folder. .. admonition:: Building wheels for multiple platforms :class: tip If our project only contains pure-Python (``.py``) code, the wheel we just built will work on all platforms, as it is a pure wheel, but if the project contains native code, it will be specific for our machine's platform. When releasing, you'll usually want to build for at least most of the other more popular platforms (Linux, Windows, macOS, etc.). To make that work easier, we recommend checking out the cibuildwheel_ project, which allows you to automate it. Distributing the project ------------------------ Now that we have the distribution artifacts, we can upload them to a repository. We will upload them to the `Python Package Index`_ (PyPI), which is repository that comes enabled by default in most tools. For this, we will use Twine_. .. code-block:: console $ pip install twine $ twine upload dist/* .. admonition:: Upload to the `Test PyPI`_ :class: tip If you don't want to upload to the real index, you can upload to the `Test PyPI`_ instead. .. code-block:: console $ twine upload -r testpypi dist/* You can find more about how to use the `Test PyPI`_ in `its PyPA documentation page `_. After this, your package should be available on PyPI_, and installable with pip_. .. code-block:: console $ pip install our-first-project .. _Meson: https://mesonbuild.com/ .. _Python module: https://mesonbuild.com/Python-module.html .. _PyPA documentation on project metadata: https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ .. _source distributions: https://packaging.python.org/en/latest/specifications/source-distribution-format/ .. _binary distributions: https://packaging.python.org/en/latest/specifications/binary-distribution-format/ .. _stable ABI: https://docs.python.org/3/c-api/stable.html#stable-application-binary-interface .. _pypa/build: https://github.com/pypa/build .. _cibuildwheel: https://github.com/pypa/cibuildwheel .. _Python Package Index: https://pypi.org/ .. _pronounced "pie pea eye": https://pypi.org/help/#pronunciation .. _Twine: https://github.com/pypa/twine .. _Test PyPI: https://test.pypi.org/ .. _PyPI: https://pypi.org/ .. _pip: https://github.com/pypa/pip ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/meson.build0000644000000000000000000000063014516424013013406 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('meson-python', version: '0.15.0') py = import('python').find_installation() py.install_sources( 'mesonpy/__init__.py', 'mesonpy/_compat.py', 'mesonpy/_editable.py', 'mesonpy/_rpath.py', 'mesonpy/_tags.py', 'mesonpy/_util.py', 'mesonpy/_wheelfile.py', subdir: 'mesonpy', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/mesonpy/__init__.py0000644000000000000000000012244214516424013015055 0ustar00# SPDX-FileCopyrightText: 2021 Filipe Laíns # SPDX-FileCopyrightText: 2021 Quansight, LLC # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT """Meson Python build backend Implements PEP 517 hooks. """ from __future__ import annotations import argparse import collections import contextlib import difflib import functools import importlib.machinery import io import json import os import pathlib import platform import re import shutil import subprocess import sys import sysconfig import tarfile import tempfile import textwrap import time import typing import warnings if sys.version_info < (3, 11): import tomli as tomllib else: import tomllib import packaging.utils import packaging.version import pyproject_metadata import mesonpy._compat import mesonpy._rpath import mesonpy._tags import mesonpy._util import mesonpy._wheelfile from mesonpy._compat import cached_property, read_binary if typing.TYPE_CHECKING: # pragma: no cover from typing import Any, Callable, DefaultDict, Dict, List, Literal, Optional, Sequence, TextIO, Tuple, Type, TypeVar, Union from mesonpy._compat import Collection, Iterator, Mapping, ParamSpec, Path P = ParamSpec('P') T = TypeVar('T') MesonArgsKeys = Literal['dist', 'setup', 'compile', 'install'] MesonArgs = Mapping[MesonArgsKeys, List[str]] __version__ = '0.15.0' _NINJA_REQUIRED_VERSION = '1.8.2' _MESON_REQUIRED_VERSION = '0.63.3' # keep in sync with the version requirement in pyproject.toml _MESON_ARGS_KEYS = ['dist', 'setup', 'compile', 'install'] _SUFFIXES = importlib.machinery.all_suffixes() _EXTENSION_SUFFIX_REGEX = re.compile(r'^[^.]+\.(?:(?P[^.]+)\.)?(?:so|pyd|dll)$') assert all(re.match(_EXTENSION_SUFFIX_REGEX, f'foo{x}') for x in importlib.machinery.EXTENSION_SUFFIXES) # Map Meson installation path placeholders to wheel installation paths. # See https://docs.python.org/3/library/sysconfig.html#installation-paths _INSTALLATION_PATH_MAP = { '{bindir}': 'scripts', '{py_purelib}': 'purelib', '{py_platlib}': 'platlib', '{moduledir_shared}': 'platlib', '{includedir}': 'headers', '{datadir}': 'data', # custom location '{libdir}': 'mesonpy-libs', '{libdir_shared}': 'mesonpy-libs', } def _map_to_wheel(sources: Dict[str, Dict[str, Any]]) -> DefaultDict[str, List[Tuple[pathlib.Path, str]]]: """Map files to the wheel, organized by wheel installation directory.""" wheel_files: DefaultDict[str, List[Tuple[pathlib.Path, str]]] = collections.defaultdict(list) packages: Dict[str, str] = {} for key, group in sources.items(): for src, target in group.items(): destination = pathlib.Path(target['destination']) anchor = destination.parts[0] dst = pathlib.Path(*destination.parts[1:]) path = _INSTALLATION_PATH_MAP.get(anchor) if path is None: raise BuildError(f'Could not map installation path to an equivalent wheel directory: {str(destination)!r}') if path == 'purelib' or path == 'platlib': package = destination.parts[1] other = packages.setdefault(package, path) if other != path: this = os.fspath(pathlib.Path(path, *destination.parts[1:])) that = os.fspath(other / next(d for d, s in wheel_files[other] if d.parts[0] == destination.parts[1])) raise BuildError( f'The {package} package is split between {path} and {other}: ' f'{this!r} and {that!r}, a "pure: false" argument may be missing in meson.build. ' f'It is recommended to set it in "import(\'python\').find_installation()"') if key == 'install_subdirs': assert os.path.isdir(src) exclude_files = {os.path.normpath(x) for x in target.get('exclude_files', [])} exclude_dirs = {os.path.normpath(x) for x in target.get('exclude_dirs', [])} for root, dirnames, filenames in os.walk(src): for name in dirnames.copy(): dirsrc = os.path.join(root, name) relpath = os.path.relpath(dirsrc, src) if relpath in exclude_dirs: dirnames.remove(name) # sort to process directories determninistically dirnames.sort() for name in sorted(filenames): filesrc = os.path.join(root, name) relpath = os.path.relpath(filesrc, src) if relpath in exclude_files: continue filedst = dst / relpath wheel_files[path].append((filedst, filesrc)) else: wheel_files[path].append((dst, src)) return wheel_files class style: ERROR = '\33[31m', # red WARNING = '\33[93m' # bright yellow INFO = '\33[36m\33[1m' # cyan, bold RESET = '\33[0m' @staticmethod def strip(string: str) -> str: """Strip ANSI escape sequences from string.""" return re.sub(r'\033\[[;?0-9]*[a-zA-Z]', '', string) @functools.lru_cache() def _use_ansi_colors() -> bool: """Determine whether logging should use ANSI color escapes.""" if 'NO_COLOR' in os.environ: return False if 'FORCE_COLOR' in os.environ or sys.stdout.isatty() and os.environ.get('TERM') != 'dumb': try: import colorama except ModuleNotFoundError: pass else: colorama.init() return True return False def _log(string: str , **kwargs: Any) -> None: if not _use_ansi_colors(): string = style.strip(string) print(string, **kwargs) def _showwarning( message: Union[Warning, str], category: Type[Warning], filename: str, lineno: int, file: Optional[TextIO] = None, line: Optional[str] = None, ) -> None: # pragma: no cover """Callable to override the default warning handler, to have colored output.""" _log(f'{style.WARNING}meson-python: warning:{style.RESET} {message}') class Error(RuntimeError): def __str__(self) -> str: return str(self.args[0]) class ConfigError(Error): """Error in the backend configuration.""" class BuildError(Error): """Error when building the wheel.""" class MesonBuilderError(Error): """Error when building the Meson package.""" class Metadata(pyproject_metadata.StandardMetadata): def __init__(self, name: str, *args: Any, **kwargs: Any): super().__init__(name, *args, **kwargs) # Local fix for https://github.com/FFY00/python-pyproject-metadata/issues/60 self.name = self._validate_name(name) @staticmethod def _validate_name(name: str) -> str: # See https://packaging.python.org/en/latest/specifications/core-metadata/#name if not re.match(r'^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$', name, re.IGNORECASE): raise pyproject_metadata.ConfigurationError( f'Invalid project name "{name}". A valid name consists only of ASCII letters and ' f'numbers, period, underscore and hyphen. It must start and end with a letter or number') return name @classmethod def from_pyproject(cls, data: Mapping[str, Any], project_dir: Path) -> Metadata: # type: ignore[override] # The class method from the pyproject_metadata base class is not # typed in a subclassing friendly way, thus annotations to ignore # typing are needed. metadata = super().from_pyproject(data, project_dir) # Check for missing version field. if not metadata.version and 'version' not in metadata.dynamic: raise pyproject_metadata.ConfigurationError( 'Required "project.version" field is missing and not declared as dynamic') # Check for unsupported dynamic fields. unsupported_dynamic = set(metadata.dynamic) - {'version', } if unsupported_dynamic: fields = ', '.join(f'"{x}"' for x in unsupported_dynamic) raise pyproject_metadata.ConfigurationError(f'Unsupported dynamic fields: {fields}') return metadata # type: ignore[return-value] # Local fix for a bug in pyproject-metadata. See # https://github.com/mesonbuild/meson-python/issues/454 def _update_dynamic(self, value: Any) -> None: if value and 'version' in self.dynamic: self.dynamic.remove('version') @property def canonical_name(self) -> str: # See https://packaging.python.org/en/latest/specifications/name-normalization/#normalization return packaging.utils.canonicalize_name(self.name) @property def distribution_name(self) -> str: """Name to be used in wheel and sdist file names.""" return self.canonical_name.replace('-', '_') def _is_native(file: Path) -> bool: """Check if file is a native file.""" with open(file, 'rb') as f: if sys.platform == 'darwin': return f.read(4) in ( b'\xfe\xed\xfa\xce', # 32-bit b'\xfe\xed\xfa\xcf', # 64-bit b'\xcf\xfa\xed\xfe', # arm64 b'\xca\xfe\xba\xbe', # universal / fat (same as java class so beware!) ) elif sys.platform == 'win32' or sys.platform == 'cygwin': return f.read(2) == b'MZ' else: # Assume that any other platform uses ELF binaries. return f.read(4) == b'\x7fELF' # ELF class _WheelBuilder(): """Helper class to build wheels from projects.""" def __init__( self, metadata: Metadata, manifest: Dict[str, List[Tuple[pathlib.Path, str]]], limited_api: bool, ) -> None: self._metadata = metadata self._manifest = manifest self._limited_api = limited_api @property def _has_internal_libs(self) -> bool: return bool(self._manifest.get('mesonpy-libs')) @property def _has_extension_modules(self) -> bool: # Assume that all code installed in {platlib} is Python ABI dependent. return bool(self._manifest.get('platlib')) @cached_property def _pure(self) -> bool: """Whether the wheel is architecture independent""" if self._manifest['platlib']: return False for _, file in self._manifest['scripts']: if _is_native(file): return False return True @property def tag(self) -> mesonpy._tags.Tag: """Wheel tags.""" if self._pure: return mesonpy._tags.Tag('py3', 'none', 'any') if not self._has_extension_modules: # The wheel has platform dependent code (is not pure) but # does not contain any extension module (does not # distribute any file in {platlib}) thus use generic # implementation and ABI tags. return mesonpy._tags.Tag('py3', 'none', None) return mesonpy._tags.Tag(None, self._stable_abi, None) @property def name(self) -> str: """Wheel name, this includes the basename and tag.""" return f'{self._metadata.distribution_name}-{self._metadata.version}-{self.tag}' @property def _distinfo_dir(self) -> str: return f'{self._metadata.distribution_name}-{self._metadata.version}.dist-info' @property def _data_dir(self) -> str: return f'{self._metadata.distribution_name}-{self._metadata.version}.data' @property def _libs_dir(self) -> str: return f'.{self._metadata.distribution_name}.mesonpy.libs' @property def _license_file(self) -> Optional[pathlib.Path]: license_ = self._metadata.license if license_: return license_.file return None @property def wheel(self) -> bytes: """Return WHEEL file for dist-info.""" return textwrap.dedent(''' Wheel-Version: 1.0 Generator: meson Root-Is-Purelib: {is_purelib} Tag: {tag} ''').strip().format( is_purelib='true' if self._pure else 'false', tag=self.tag, ).encode() @property def entrypoints_txt(self) -> bytes: """dist-info entry_points.txt.""" data = self._metadata.entrypoints.copy() data.update({ 'console_scripts': self._metadata.scripts, 'gui_scripts': self._metadata.gui_scripts, }) text = '' for entrypoint in data: if data[entrypoint]: text += f'[{entrypoint}]\n' for name, target in data[entrypoint].items(): text += f'{name} = {target}\n' text += '\n' return text.encode() @cached_property def _stable_abi(self) -> Optional[str]: if self._limited_api: # PyPy does not use a special extension module filename # suffix for modules targeting the stable API. if '__pypy__' not in sys.builtin_module_names: # Verify stable ABI compatibility: examine files installed # in {platlib} that look like extension modules, and raise # an exception if any of them has a Python version # specific extension filename suffix ABI tag. for path, _ in self._manifest['platlib']: match = _EXTENSION_SUFFIX_REGEX.match(path.name) if match: abi = match.group('abi') if abi is not None and abi != 'abi3': raise BuildError( f'The package declares compatibility with Python limited API but extension ' f'module {os.fspath(path)!r} is tagged for a specific Python version.') return 'abi3' return None def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile, origin: Path, destination: pathlib.Path) -> None: """Add a file to the wheel.""" if self._has_internal_libs: if _is_native(origin): # When an executable, libray, or Python extension module is # dynamically linked to a library built as part of the project, # Meson adds a library load path to it pointing to the build # directory, in the form of a relative RPATH entry. meson-python # relocates the shared libraries to the $project.mesonpy.libs # folder. Rewrite the RPATH to point to that folder instead. libspath = os.path.relpath(self._libs_dir, destination.parent) mesonpy._rpath.fix_rpath(origin, libspath) try: wheel_file.write(origin, destination.as_posix()) except FileNotFoundError: # work around for Meson bug, see https://github.com/mesonbuild/meson/pull/11655 if not os.fspath(origin).endswith('.pdb'): raise def _wheel_write_metadata(self, whl: mesonpy._wheelfile.WheelFile) -> None: # add metadata whl.writestr(f'{self._distinfo_dir}/METADATA', bytes(self._metadata.as_rfc822())) whl.writestr(f'{self._distinfo_dir}/WHEEL', self.wheel) if self.entrypoints_txt: whl.writestr(f'{self._distinfo_dir}/entry_points.txt', self.entrypoints_txt) # add license (see https://github.com/mesonbuild/meson-python/issues/88) if self._license_file: whl.write(self._license_file, f'{self._distinfo_dir}/{os.path.basename(self._license_file)}') def build(self, directory: Path) -> pathlib.Path: wheel_file = pathlib.Path(directory, f'{self.name}.whl') with mesonpy._wheelfile.WheelFile(wheel_file, 'w') as whl: self._wheel_write_metadata(whl) with mesonpy._util.clicounter(sum(len(x) for x in self._manifest.values())) as counter: root = 'purelib' if self._pure else 'platlib' for path, entries in self._manifest.items(): for dst, src in entries: counter.update(src) if path == root: pass elif path == 'mesonpy-libs': # custom installation path for bundled libraries dst = pathlib.Path(self._libs_dir, dst) else: dst = pathlib.Path(self._data_dir, path, dst) self._install_path(whl, src, dst) return wheel_file class _EditableWheelBuilder(_WheelBuilder): @property def _top_level_modules(self) -> Collection[str]: modules = set() for type_ in self._manifest: for path, _ in self._manifest[type_]: name, dot, ext = path.parts[0].partition('.') if dot: # module suffix = dot + ext if suffix in _SUFFIXES: modules.add(name) else: # package modules.add(name) return modules def build(self, directory: Path, source_dir: pathlib.Path, build_dir: pathlib.Path, # type: ignore[override] build_command: List[str], verbose: bool = False) -> pathlib.Path: wheel_file = pathlib.Path(directory, f'{self.name}.whl') with mesonpy._wheelfile.WheelFile(wheel_file, 'w') as whl: self._wheel_write_metadata(whl) whl.writestr( f'{self._distinfo_dir}/direct_url.json', source_dir.as_uri().encode('utf-8')) # install loader module loader_module_name = f'_{self._metadata.distribution_name}_editable_loader' whl.writestr( f'{loader_module_name}.py', read_binary('mesonpy', '_editable.py') + textwrap.dedent(f''' install( {self._top_level_modules!r}, {os.fspath(build_dir)!r}, {build_command!r}, {verbose!r}, )''').encode('utf-8')) # install .pth file whl.writestr( f'{self._metadata.canonical_name}-editable.pth', f'import {loader_module_name}'.encode('utf-8')) return wheel_file def _validate_pyproject_config(pyproject: Dict[str, Any]) -> Dict[str, Any]: def _table(scheme: Dict[str, Callable[[Any, str], Any]]) -> Callable[[Any, str], Dict[str, Any]]: def func(value: Any, name: str) -> Dict[str, Any]: if not isinstance(value, dict): raise ConfigError(f'Configuration entry "{name}" must be a table') table = {} for key, val in value.items(): check = scheme.get(key) if check is None: raise ConfigError(f'Unknown configuration entry "{name}.{key}"') table[key] = check(val, f'{name}.{key}') return table return func def _strings(value: Any, name: str) -> List[str]: if not isinstance(value, list) or not all(isinstance(x, str) for x in value): raise ConfigError(f'Configuration entry "{name}" must be a list of strings') return value def _bool(value: Any, name: str) -> bool: if not isinstance(value, bool): raise ConfigError(f'Configuration entry "{name}" must be a boolean') return value def _string_or_path(value: Any, name: str) -> str: if not isinstance(value, str): raise ConfigError(f'Configuration entry "{name}" must be a string') if os.path.isfile(value): value = os.path.abspath(value) return value scheme = _table({ 'meson': _string_or_path, 'limited-api': _bool, 'args': _table({ name: _strings for name in _MESON_ARGS_KEYS }), }) table = pyproject.get('tool', {}).get('meson-python', {}) return scheme(table, 'tool.meson-python') def _validate_config_settings(config_settings: Dict[str, Any]) -> Dict[str, Any]: """Validate options received from build frontend.""" def _string(value: Any, name: str) -> str: if not isinstance(value, str): raise ConfigError(f'Only one value for "{name}" can be specified') return value def _bool(value: Any, name: str) -> bool: return True def _string_or_strings(value: Any, name: str) -> List[str]: return list([value,] if isinstance(value, str) else value) options = { 'builddir': _string, 'build-dir': _string, 'editable-verbose': _bool, 'dist-args': _string_or_strings, 'setup-args': _string_or_strings, 'compile-args': _string_or_strings, 'install-args': _string_or_strings, } assert all(f'{name}-args' in options for name in _MESON_ARGS_KEYS) config = {} for key, value in config_settings.items(): parser = options.get(key) if parser is None: matches = difflib.get_close_matches(key, options.keys(), n=2) if matches: alternatives = ' or '.join(f'"{match}"' for match in matches) raise ConfigError(f'Unknown option "{key}". Did you mean {alternatives}?') else: raise ConfigError(f'Unknown option "{key}"') config[key] = parser(value, key) # Check backward compatibility aliases. aliases = { 'build-dir': 'builddir', } for key, alt in aliases.items(): if key in config and alt in config: raise ConfigError(f'Option "{alt}" is a backward compatibility alias for "{key}". Only one can be used') if alt in config: config[key] = config[alt] return config class Project(): """Meson project wrapper to generate Python artifacts.""" def __init__( self, source_dir: Path, build_dir: Path, meson_args: Optional[MesonArgs] = None, editable_verbose: bool = False, ) -> None: self._source_dir = pathlib.Path(source_dir).absolute() self._build_dir = pathlib.Path(build_dir).absolute() self._editable_verbose = editable_verbose self._meson_native_file = self._build_dir / 'meson-python-native-file.ini' self._meson_cross_file = self._build_dir / 'meson-python-cross-file.ini' self._meson_args: MesonArgs = collections.defaultdict(list) self._limited_api = False # load pyproject.toml pyproject = tomllib.loads(self._source_dir.joinpath('pyproject.toml').read_text()) # load meson args from pyproject.toml pyproject_config = _validate_pyproject_config(pyproject) for key, value in pyproject_config.get('args', {}).items(): self._meson_args[key].extend(value) # meson arguments from the command line take precedence over # arguments from the configuration file thus are added later if meson_args: for key, value in meson_args.items(): self._meson_args[key].extend(value) # determine command to invoke meson self._meson = _get_meson_command(pyproject_config.get('meson')) self._ninja = _env_ninja_command() if self._ninja is None: raise ConfigError(f'Could not find ninja version {_NINJA_REQUIRED_VERSION} or newer.') os.environ.setdefault('NINJA', self._ninja) # make sure the build dir exists self._build_dir.mkdir(exist_ok=True, parents=True) # setuptools-like ARCHFLAGS environment variable support if sysconfig.get_platform().startswith('macosx-'): archflags = os.environ.get('ARCHFLAGS', '').strip() if archflags: arch, *other = filter(None, (x.strip() for x in archflags.split('-arch'))) if other: raise ConfigError(f'Multi-architecture builds are not supported but $ARCHFLAGS={archflags!r}') macver, _, nativearch = platform.mac_ver() if arch != nativearch: x = os.environ.setdefault('_PYTHON_HOST_PLATFORM', f'macosx-{macver}-{arch}') if not x.endswith(arch): raise ConfigError(f'$ARCHFLAGS={archflags!r} and $_PYTHON_HOST_PLATFORM={x!r} do not agree') family = 'aarch64' if arch == 'arm64' else arch cross_file_data = textwrap.dedent(f''' [binaries] c = ['cc', '-arch', {arch!r}] cpp = ['c++', '-arch', {arch!r}] objc = ['cc', '-arch', {arch!r}] objcpp = ['c++', '-arch', {arch!r}] [host_machine] system = 'darwin' cpu = {arch!r} cpu_family = {family!r} endian = 'little' ''') self._meson_cross_file.write_text(cross_file_data) self._meson_args['setup'].extend(('--cross-file', os.fspath(self._meson_cross_file))) # write the native file native_file_data = textwrap.dedent(f''' [binaries] python = '{sys.executable}' ''') self._meson_native_file.write_text(native_file_data) # reconfigure if we have a valid Meson build directory. Meson # uses the presence of the 'meson-private/coredata.dat' file # in the build directory as indication that the build # directory has already been configured and arranges this file # to be created as late as possible or deleted if something # goes wrong during setup. reconfigure = self._build_dir.joinpath('meson-private/coredata.dat').is_file() # run meson setup self._configure(reconfigure=reconfigure) # package metadata if 'project' in pyproject: self._metadata = Metadata.from_pyproject(pyproject, self._source_dir) # set version from meson.build if version is declared as dynamic if 'version' in self._metadata.dynamic: version = self._meson_version if version == 'undefined': raise pyproject_metadata.ConfigurationError( 'Field "version" declared as dynamic but version is not defined in meson.build') self._metadata.version = packaging.version.Version(version) else: # if project section is missing, use minimal metdata from meson.build name, version = self._meson_name, self._meson_version if version == 'undefined': raise pyproject_metadata.ConfigurationError( 'Section "project" missing in pyproject.toml and version is not defined in meson.build') self._metadata = Metadata(name=name, version=packaging.version.Version(version)) # verify that we are running on a supported interpreter if self._metadata.requires_python: self._metadata.requires_python.prereleases = True if platform.python_version().rstrip('+') not in self._metadata.requires_python: raise MesonBuilderError( f'Package requires Python version {self._metadata.requires_python}, ' f'running on {platform.python_version()}') # limited API self._limited_api = pyproject_config.get('limited-api', False) if self._limited_api: # check whether limited API is disabled for the Meson project options = self._info('intro-buildoptions') value = next((option['value'] for option in options if option['name'] == 'python.allow_limited_api'), None) if not value: self._limited_api = False def _run(self, cmd: Sequence[str]) -> None: """Invoke a subprocess.""" # Flush the line to ensure that the log line with the executed # command line appears before the command output. Without it, # the lines appear in the wrong order in pip output. _log('{style.INFO}+ {cmd}{style.RESET}'.format(style=style, cmd=' '.join(cmd)), flush=True) r = subprocess.run(cmd, cwd=self._build_dir) if r.returncode != 0: raise SystemExit(r.returncode) def _configure(self, reconfigure: bool = False) -> None: """Configure Meson project.""" setup_args = [ os.fspath(self._source_dir), os.fspath(self._build_dir), # default build options '-Dbuildtype=release', '-Db_ndebug=if-release', '-Db_vscrt=md', # user build options *self._meson_args['setup'], # pass native file last to have it override the python # interpreter path that may have been specified in user # provided native files f'--native-file={os.fspath(self._meson_native_file)}', ] if reconfigure: setup_args.insert(0, '--reconfigure') self._run(self._meson + ['setup', *setup_args]) @property def _build_command(self) -> List[str]: assert self._ninja is not None # help mypy out if sys.platform == 'win32': # On Windows use 'meson compile' to setup the MSVC compiler # environment. Using the --ninja-args option allows to # provide the exact same semantics for the compile arguments # provided by the users. cmd = self._meson + ['compile'] args = list(self._meson_args['compile']) if args: cmd.append(f'--ninja-args={args!r}') return cmd return [self._ninja, *self._meson_args['compile']] @functools.lru_cache(maxsize=None) def build(self) -> None: """Build the Meson project.""" self._run(self._build_command) @functools.lru_cache() def _info(self, name: str) -> Any: """Read info from meson-info directory.""" info = self._build_dir.joinpath('meson-info', f'{name}.json') return json.loads(info.read_text()) @property def _manifest(self) -> DefaultDict[str, List[Tuple[pathlib.Path, str]]]: """The files to be added to the wheel, organized by wheel path.""" # Obtain the list of files Meson would install. install_plan = self._info('intro-install_plan') # Parse the 'meson install' args to extract --tags and --skip-subprojects parser = argparse.ArgumentParser() parser.add_argument('--tags') parser.add_argument('--skip-subprojects', nargs='?', const='*', default='') args, _ = parser.parse_known_args(self._meson_args['install']) install_tags = {t.strip() for t in args.tags.split(',')} if args.tags else None skip_subprojects = {p for p in (p.strip() for p in args.skip_subprojects.split(',')) if p} # Filter the install plan accordingly. sources: DefaultDict[str, Dict[str, Dict[str, str]]] = collections.defaultdict(dict) for key, targets in install_plan.items(): for target, details in targets.items(): if install_tags is not None and details['tag'] not in install_tags: continue subproject = details.get('subproject') if subproject is not None and (subproject in skip_subprojects or '*' in skip_subprojects): continue sources[key][target] = details # Map Meson installation locations to wheel paths. return _map_to_wheel(sources) @property def _meson_name(self) -> str: """Name in meson.build.""" name = self._info('intro-projectinfo')['descriptive_name'] assert isinstance(name, str) return name @property def _meson_version(self) -> str: """Version in meson.build.""" name = self._info('intro-projectinfo')['version'] assert isinstance(name, str) return name def sdist(self, directory: Path) -> pathlib.Path: """Generates a sdist (source distribution) in the specified directory.""" # generate meson dist file self._run(self._meson + ['dist', '--allow-dirty', '--no-tests', '--formats', 'gztar', *self._meson_args['dist']]) # move meson dist file to output path dist_name = f'{self._metadata.distribution_name}-{self._metadata.version}' meson_dist_name = f'{self._meson_name}-{self._meson_version}' meson_dist_path = pathlib.Path(self._build_dir, 'meson-dist', f'{meson_dist_name}.tar.gz') sdist = pathlib.Path(directory, f'{dist_name}.tar.gz') with tarfile.open(meson_dist_path, 'r:gz') as meson_dist, mesonpy._util.create_targz(sdist) as tar: for member in meson_dist.getmembers(): # calculate the file path in the source directory assert member.name, member.name member_parts = member.name.split('/') if len(member_parts) <= 1: continue path = self._source_dir.joinpath(*member_parts[1:]) if not path.exists() and member.isfile(): # File doesn't exists on the source directory but exists on # the Meson dist, so it is generated file, which we need to # include. # See https://mesonbuild.com/Reference-manual_builtin_meson.html#mesonadd_dist_script # MESON_DIST_ROOT could have a different base name # than the actual sdist basename, so we need to rename here file = meson_dist.extractfile(member.name) member.name = str(pathlib.Path(dist_name, *member_parts[1:]).as_posix()) tar.addfile(member, file) continue if not path.is_file(): continue info = tarfile.TarInfo(member.name) file_stat = os.stat(path) info.mtime = member.mtime info.size = file_stat.st_size info.mode = int(oct(file_stat.st_mode)[-3:], 8) # rewrite the path if necessary, to match the sdist distribution name if dist_name != meson_dist_name: info.name = pathlib.Path( dist_name, path.relative_to(self._source_dir) ).as_posix() with path.open('rb') as f: tar.addfile(info, fileobj=f) # add PKG-INFO to dist file to make it a sdist pkginfo_info = tarfile.TarInfo(f'{dist_name}/PKG-INFO') pkginfo_info.mtime = time.time() # type: ignore[assignment] metadata = bytes(self._metadata.as_rfc822()) pkginfo_info.size = len(metadata) tar.addfile(pkginfo_info, fileobj=io.BytesIO(metadata)) return sdist def wheel(self, directory: Path) -> pathlib.Path: """Generates a wheel in the specified directory.""" self.build() builder = _WheelBuilder(self._metadata, self._manifest, self._limited_api) return builder.build(directory) def editable(self, directory: Path) -> pathlib.Path: """Generates an editable wheel in the specified directory.""" self.build() builder = _EditableWheelBuilder(self._metadata, self._manifest, self._limited_api) return builder.build(directory, self._source_dir, self._build_dir, self._build_command, self._editable_verbose) @contextlib.contextmanager def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Project]: """Create the project given the given config settings.""" settings = _validate_config_settings(config_settings or {}) meson_args = typing.cast('MesonArgs', {name: settings.get(f'{name}-args', []) for name in _MESON_ARGS_KEYS}) source_dir = os.path.curdir build_dir = settings.get('build-dir') editable_verbose = bool(settings.get('editable-verbose')) with contextlib.ExitStack() as ctx: if build_dir is None: build_dir = ctx.enter_context(tempfile.TemporaryDirectory(prefix='.mesonpy-', dir=source_dir)) yield Project(source_dir, build_dir, meson_args, editable_verbose) def _parse_version_string(string: str) -> Tuple[int, ...]: """Parse version string.""" try: return tuple(map(int, string.split('.')[:3])) except ValueError: return (0, ) def _get_meson_command( meson: Optional[str] = None, *, version: str = _MESON_REQUIRED_VERSION ) -> List[str]: """Return the command to invoke meson.""" # The MESON env var, if set, overrides the config value from pyproject.toml. # The config value, if given, is an absolute path or the name of an executable. meson = os.environ.get('MESON', meson or 'meson') # If the specified Meson string ends in `.py`, we run it with the current # Python executable. This avoids problems for users on Windows, where # making a script executable isn't enough to get it to run when invoked # directly. For packages that vendor a forked Meson, the `meson.py` in the # root of the Meson repo can be used this way. if meson.endswith('.py'): cmd = [sys.executable, meson] else: cmd = [meson] # The meson Python package is a dependency of the meson-python Python # package, however, it may occur that the meson Python package is installed # but the corresponding meson command is not available in $PATH. Implement # a runtime check to verify that the build environment is setup correcly. required_version = _parse_version_string(version) meson_version = subprocess.run(cmd + ['--version'], check=False, text=True, capture_output=True).stdout if _parse_version_string(meson_version) < required_version: raise ConfigError(f'Could not find meson version {version} or newer, found {meson_version}.') return cmd def _env_ninja_command(*, version: str = _NINJA_REQUIRED_VERSION) -> Optional[str]: """Returns the path to ninja, or None if no ninja found.""" required_version = _parse_version_string(version) env_ninja = os.environ.get('NINJA') ninja_candidates = [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu'] for ninja in ninja_candidates: ninja_path = shutil.which(ninja) if ninja_path is not None: version = subprocess.run([ninja_path, '--version'], check=False, text=True, capture_output=True).stdout if _parse_version_string(version) >= required_version: return ninja_path return None def _add_ignore_files(directory: pathlib.Path) -> None: directory.joinpath('.gitignore').write_text(textwrap.dedent(''' # This file is generated by meson-python. It will not be recreated if deleted or modified. * '''), encoding='utf-8') directory.joinpath('.hgignore').write_text(textwrap.dedent(''' # This file is generated by meson-python. It will not be recreated if deleted or modified. syntax: glob **/* '''), encoding='utf-8') def _pyproject_hook(func: Callable[P, T]) -> Callable[P, T]: @functools.wraps(func) def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: warnings.showwarning = _showwarning try: return func(*args, **kwargs) except (Error, pyproject_metadata.ConfigurationError) as exc: prefix = f'{style.ERROR}meson-python: error:{style.RESET} ' _log('\n' + textwrap.indent(str(exc), prefix)) raise SystemExit(1) from exc return wrapper @_pyproject_hook def get_requires_for_build_sdist(config_settings: Optional[Dict[str, str]] = None) -> List[str]: dependencies = [] if os.environ.get('NINJA') is None and _env_ninja_command() is None: dependencies.append(f'ninja >= {_NINJA_REQUIRED_VERSION}') return dependencies @_pyproject_hook def get_requires_for_build_wheel(config_settings: Optional[Dict[str, str]] = None) -> List[str]: dependencies = [] if os.environ.get('NINJA') is None and _env_ninja_command() is None: dependencies.append(f'ninja >= {_NINJA_REQUIRED_VERSION}') if sys.platform.startswith('linux') and not shutil.which('patchelf'): dependencies.append('patchelf >= 0.11.0') return dependencies get_requires_for_build_editable = get_requires_for_build_wheel @_pyproject_hook def build_sdist( sdist_directory: str, config_settings: Optional[Dict[Any, Any]] = None, ) -> str: out = pathlib.Path(sdist_directory) with _project(config_settings) as project: return project.sdist(out).name @_pyproject_hook def build_wheel( wheel_directory: str, config_settings: Optional[Dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: out = pathlib.Path(wheel_directory) with _project(config_settings) as project: return project.wheel(out).name @_pyproject_hook def build_editable( wheel_directory: str, config_settings: Optional[Dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: # Force set a permanent build directory. if not config_settings: config_settings = {} if 'build-dir' not in config_settings and 'builddir' not in config_settings: build_dir = pathlib.Path('build') build_dir.mkdir(exist_ok=True) if not next(build_dir.iterdir(), None): _add_ignore_files(build_dir) config_settings['build-dir'] = os.fspath(build_dir / str(mesonpy._tags.get_abi_tag())) out = pathlib.Path(wheel_directory) with _project(config_settings) as project: return project.editable(out).name ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/mesonpy/_compat.py0000644000000000000000000000264214516424013014737 0ustar00# SPDX-FileCopyrightText: 2021 Filipe Laíns # SPDX-FileCopyrightText: 2021 Quansight, LLC # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import functools import importlib.resources import os import sys import typing if sys.version_info >= (3, 9): from collections.abc import Collection, Iterable, Iterator, Mapping, Sequence else: from typing import Collection, Iterable, Iterator, Mapping, Sequence if sys.version_info >= (3, 8): from functools import cached_property else: cached_property = lambda x: property(functools.lru_cache(maxsize=None)(x)) # noqa: E731 if sys.version_info >= (3, 9): def read_binary(package: str, resource: str) -> bytes: return importlib.resources.files(package).joinpath(resource).read_bytes() else: read_binary = importlib.resources.read_binary if typing.TYPE_CHECKING: from typing import Union if sys.version_info >= (3, 10): from typing import ParamSpec else: from typing_extensions import ParamSpec if sys.version_info >= (3, 11): from typing import Self else: from typing_extensions import Self Path = Union[str, os.PathLike] __all__ = [ 'cached_property', 'read_binary', 'Collection', 'Iterable', 'Iterator', 'Mapping', 'Path', 'ParamSpec', 'Self', 'Sequence', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/mesonpy/_editable.py0000644000000000000000000002430614516424013015226 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # This file should be standalone! It is copied during the editable hook installation. from __future__ import annotations import functools import importlib.abc import importlib.machinery import importlib.util import json import os import pathlib import subprocess import sys import typing if typing.TYPE_CHECKING: from collections.abc import Sequence, Set from types import ModuleType from typing import Any, Dict, Iterator, List, Optional, Tuple, Union from typing_extensions import Buffer NodeBase = Dict[str, Union['Node', str]] PathStr = Union[str, os.PathLike[str]] else: NodeBase = dict if sys.version_info >= (3, 12): from importlib.resources.abc import Traversable, TraversableResources elif sys.version_info >= (3, 9): from importlib.abc import Traversable, TraversableResources else: class Traversable: pass class TraversableResources: pass MARKER = 'MESONPY_EDITABLE_SKIP' VERBOSE = 'MESONPY_EDITABLE_VERBOSE' class MesonpyOrphan(Traversable): def __init__(self, name: str): self._name = name @property def name(self) -> str: return self._name def is_dir(self) -> bool: return False def is_file(self) -> bool: return False def iterdir(self) -> Iterator[Traversable]: raise FileNotFoundError() def open(self, *args, **kwargs): # type: ignore raise FileNotFoundError() def joinpath(self, *descendants: PathStr) -> Traversable: if not descendants: return self name = os.fspath(descendants[-1]).split('/')[-1] return MesonpyOrphan(name) def __truediv__(self, child: PathStr) -> Traversable: return self.joinpath(child) def read_bytes(self) -> bytes: raise FileNotFoundError() def read_text(self, encoding: Optional[str] = None) -> str: raise FileNotFoundError() class MesonpyTraversable(Traversable): def __init__(self, name: str, tree: Node): self._name = name self._tree = tree @property def name(self) -> str: return self._name def is_dir(self) -> bool: return True def is_file(self) -> bool: return False def iterdir(self) -> Iterator[Traversable]: for name, node in self._tree.items(): yield MesonpyTraversable(name, node) if isinstance(node, dict) else pathlib.Path(node) # type: ignore def open(self, *args, **kwargs): # type: ignore raise IsADirectoryError() @staticmethod def _flatten(names: Tuple[PathStr, ...]) -> Iterator[str]: for name in names: yield from os.fspath(name).split('/') def joinpath(self, *descendants: PathStr) -> Traversable: if not descendants: return self names = self._flatten(descendants) name = next(names) node = self._tree.get(name) if isinstance(node, dict): return MesonpyTraversable(name, node).joinpath(*names) if isinstance(node, str): return pathlib.Path(node).joinpath(*names) return MesonpyOrphan(name).joinpath(*names) def __truediv__(self, child: PathStr) -> Traversable: return self.joinpath(child) def read_bytes(self) -> bytes: raise IsADirectoryError() def read_text(self, encoding: Optional[str] = None) -> str: raise IsADirectoryError() class MesonpyReader(TraversableResources): def __init__(self, name: str, tree: Node): self._name = name self._tree = tree def files(self) -> Traversable: return MesonpyTraversable(self._name, self._tree) class ExtensionFileLoader(importlib.machinery.ExtensionFileLoader): def __init__(self, name: str, path: str, tree: Node): super().__init__(name, path) self._tree = tree def get_resource_reader(self, name: str) -> TraversableResources: return MesonpyReader(name, self._tree) class SourceFileLoader(importlib.machinery.SourceFileLoader): def __init__(self, name: str, path: str, tree: Node): super().__init__(name, path) self._tree = tree def set_data(self, path: Union[bytes, str], data: Buffer, *, _mode: int = ...) -> None: # disable saving bytecode pass def get_resource_reader(self, name: str) -> TraversableResources: return MesonpyReader(name, self._tree) class SourcelessFileLoader(importlib.machinery.SourcelessFileLoader): def __init__(self, name: str, path: str, tree: Node): super().__init__(name, path) self._tree = tree def get_resource_reader(self, name: str) -> TraversableResources: return MesonpyReader(name, self._tree) LOADERS = [ (ExtensionFileLoader, tuple(importlib.machinery.EXTENSION_SUFFIXES)), (SourceFileLoader, tuple(importlib.machinery.SOURCE_SUFFIXES)), (SourcelessFileLoader, tuple(importlib.machinery.BYTECODE_SUFFIXES)), ] def build_module_spec(cls: type, name: str, path: str, tree: Optional[Node]) -> importlib.machinery.ModuleSpec: loader = cls(name, path, tree) spec = importlib.machinery.ModuleSpec(name, loader, origin=path) spec.has_location = True if loader.is_package(name): spec.submodule_search_locations = [] return spec class Node(NodeBase): """Tree structure to store a virtual filesystem view.""" def __missing__(self, key: str) -> Node: value = self[key] = Node() return value def __setitem__(self, key: Union[str, Tuple[str, ...]], value: Union[Node, str]) -> None: node = self if isinstance(key, tuple): for k in key[:-1]: node = typing.cast(Node, node[k]) key = key[-1] dict.__setitem__(node, key, value) def __getitem__(self, key: Union[str, Tuple[str, ...]]) -> Union[Node, str]: node = self if isinstance(key, tuple): for k in key[:-1]: node = typing.cast(Node, node[k]) key = key[-1] return dict.__getitem__(node, key) def get(self, key: Union[str, Tuple[str, ...]]) -> Optional[Union[Node, str]]: # type: ignore[override] node = self if isinstance(key, tuple): for k in key[:-1]: v = dict.get(node, k) if v is None: return None node = typing.cast(Node, v) key = key[-1] return dict.get(node, key) def walk(root: str, path: str = '') -> Iterator[pathlib.Path]: with os.scandir(os.path.join(root, path)) as entries: for entry in entries: if entry.is_dir(): yield from walk(root, os.path.join(path, entry.name)) else: yield pathlib.Path(path, entry.name) def collect(install_plan: Dict[str, Dict[str, Any]]) -> Node: tree = Node() for key, data in install_plan.items(): for src, target in data.items(): path = pathlib.Path(target['destination']) if path.parts[0] in {'{py_platlib}', '{py_purelib}'}: if key == 'install_subdirs' and os.path.isdir(src): for entry in walk(src): tree[(*path.parts[1:], *entry.parts)] = os.path.join(src, *entry.parts) else: tree[path.parts[1:]] = src return tree class MesonpyMetaFinder(importlib.abc.MetaPathFinder): def __init__(self, names: Set[str], path: str, cmd: List[str], verbose: bool = False): self._top_level_modules = names self._build_path = path self._build_cmd = cmd self._verbose = verbose self._loaders: List[Tuple[type, str]] = [] for loader, suffixes in LOADERS: self._loaders.extend((loader, suffix) for suffix in suffixes) def __repr__(self) -> str: return f'{self.__class__.__name__}({self._build_path!r})' def find_spec( self, fullname: str, path: Optional[Sequence[Union[bytes, str]]] = None, target: Optional[ModuleType] = None ) -> Optional[importlib.machinery.ModuleSpec]: if fullname.split('.', maxsplit=1)[0] in self._top_level_modules: if self._build_path in os.environ.get(MARKER, '').split(os.pathsep): return None namespace = False tree = self.rebuild() parts = fullname.split('.') # look for a package package = tree.get(tuple(parts)) if isinstance(package, Node): for loader, suffix in self._loaders: src = package.get('__init__' + suffix) if isinstance(src, str): return build_module_spec(loader, fullname, src, package) else: namespace = True # look for a module for loader, suffix in self._loaders: src = tree.get((*parts[:-1], parts[-1] + suffix)) if isinstance(src, str): return build_module_spec(loader, fullname, src, None) # namespace if namespace: spec = importlib.machinery.ModuleSpec(fullname, None) spec.submodule_search_locations = [] return spec return None @functools.lru_cache(maxsize=1) def rebuild(self) -> Node: # skip editable wheel lookup during rebuild: during the build # the module we are rebuilding might be imported causing a # rebuild loop. env = os.environ.copy() env[MARKER] = os.pathsep.join((env.get(MARKER, ''), self._build_path)) if self._verbose or bool(env.get(VERBOSE, '')): print('+ ' + ' '.join(self._build_cmd)) stdout = None else: stdout = subprocess.DEVNULL subprocess.run(self._build_cmd, cwd=self._build_path, env=env, stdout=stdout, check=True) install_plan_path = os.path.join(self._build_path, 'meson-info', 'intro-install_plan.json') with open(install_plan_path, 'r', encoding='utf8') as f: install_plan = json.load(f) return collect(install_plan) def install(names: Set[str], path: str, cmd: List[str], verbose: bool) -> None: sys.meta_path.insert(0, MesonpyMetaFinder(names, path, cmd, verbose)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/mesonpy/_rpath.py0000644000000000000000000000420514516424013014567 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import os import subprocess import sys import typing if typing.TYPE_CHECKING: from typing import List from mesonpy._compat import Iterable, Path if sys.platform == 'linux': def _get_rpath(filepath: Path) -> List[str]: r = subprocess.run(['patchelf', '--print-rpath', os.fspath(filepath)], capture_output=True, text=True) return r.stdout.strip().split(':') def _set_rpath(filepath: Path, rpath: Iterable[str]) -> None: subprocess.run(['patchelf','--set-rpath', ':'.join(rpath), os.fspath(filepath)], check=True) def fix_rpath(filepath: Path, libs_relative_path: str) -> None: old_rpath = _get_rpath(filepath) new_rpath = [] for path in old_rpath: if path.startswith('$ORIGIN/'): path = '$ORIGIN/' + libs_relative_path new_rpath.append(path) if new_rpath != old_rpath: _set_rpath(filepath, new_rpath) elif sys.platform == 'darwin': def _get_rpath(filepath: Path) -> List[str]: rpath = [] r = subprocess.run(['otool', '-l', os.fspath(filepath)], capture_output=True, text=True) rpath_tag = False for line in [x.split() for x in r.stdout.split('\n')]: if line == ['cmd', 'LC_RPATH']: rpath_tag = True elif len(line) >= 2 and line[0] == 'path' and rpath_tag: rpath.append(line[1]) rpath_tag = False return rpath def _replace_rpath(filepath: Path, old: str, new: str) -> None: subprocess.run(['install_name_tool', '-rpath', old, new, os.fspath(filepath)], check=True) def fix_rpath(filepath: Path, libs_relative_path: str) -> None: for path in _get_rpath(filepath): if path.startswith('@loader_path/'): _replace_rpath(filepath, path, '@loader_path/' + libs_relative_path) else: def fix_rpath(filepath: Path, libs_relative_path: str) -> None: raise NotImplementedError(f'Bundling libraries in wheel is not supported on {sys.platform}') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/mesonpy/_tags.py0000644000000000000000000001375214516424013014416 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import os import platform import sys import sysconfig import typing if typing.TYPE_CHECKING: # pragma: no cover from typing import Optional, Union # https://peps.python.org/pep-0425/#python-tag INTERPRETERS = { 'python': 'py', 'cpython': 'cp', 'pypy': 'pp', 'ironpython': 'ip', 'jython': 'jy', } _32_BIT_INTERPRETER = sys.maxsize <= 2**32 def get_interpreter_tag() -> str: name = sys.implementation.name name = INTERPRETERS.get(name, name) version = sys.version_info return f'{name}{version[0]}{version[1]}' def _get_config_var(name: str, default: Union[str, int, None] = None) -> Union[str, int, None]: value: Union[str, int, None] = sysconfig.get_config_var(name) if value is None: return default return value def _get_cpython_abi() -> str: version = sys.version_info debug = pymalloc = '' if _get_config_var('Py_DEBUG', hasattr(sys, 'gettotalrefcount')): debug = 'd' if version < (3, 8) and _get_config_var('WITH_PYMALLOC', True): pymalloc = 'm' return f'cp{version[0]}{version[1]}{debug}{pymalloc}' def get_abi_tag() -> str: # The best solution to obtain the Python ABI is to parse the # $SOABI or $EXT_SUFFIX sysconfig variables as defined in PEP-314. # PyPy reports a $SOABI that does not agree with $EXT_SUFFIX. # Using $EXT_SUFFIX will not break when PyPy will fix this. # See https://foss.heptapod.net/pypy/pypy/-/issues/3816 and # https://github.com/pypa/packaging/pull/607. try: empty, abi, ext = str(sysconfig.get_config_var('EXT_SUFFIX')).split('.') except ValueError as exc: # CPython <= 3.8.7 on Windows does not implement PEP3149 and # uses '.pyd' as $EXT_SUFFIX, which does not allow to extract # the interpreter ABI. Check that the fallback is not hit for # any other Python implementation. if sys.implementation.name != 'cpython': raise NotImplementedError from exc return _get_cpython_abi() # The packaging module initially based his understanding of the # $SOABI variable on the inconsistent value reported by PyPy, and # did not strip architecture information from it. Therefore the # ABI tag for later Python implementations (all the ones not # explicitly handled below) contains architecture information too. # Unfortunately, fixing this now would break compatibility. if abi.startswith('cpython'): abi = 'cp' + abi.split('-')[1] elif abi.startswith('cp'): abi = abi.split('-')[0] elif abi.startswith('pypy'): abi = '_'.join(abi.split('-')[:2]) elif abi.startswith('graalpy'): abi = '_'.join(abi.split('-')[:3]) return abi.replace('.', '_').replace('-', '_') def _get_macosx_platform_tag() -> str: ver, _, arch = platform.mac_ver() # Override the architecture with the one provided in the # _PYTHON_HOST_PLATFORM environment variable. This environment # variable affects the sysconfig.get_platform() return value and # is used to cross-compile python extensions on macOS for a # different architecture. We base the platform tag computation on # platform.mac_ver() but respect the content of the environment # variable. try: arch = os.environ.get('_PYTHON_HOST_PLATFORM', '').split('-')[2] except IndexError: pass # Override the macOS version if one is provided via the # MACOSX_DEPLOYMENT_TARGET environment variable. try: version = tuple(map(int, os.environ.get('MACOSX_DEPLOYMENT_TARGET', '').split('.')))[:2] except ValueError: version = tuple(map(int, ver.split('.')))[:2] # Python built with older macOS SDK on macOS 11, reports an # unexising macOS 10.16 version instead of the real version. # # The packaging module introduced a workaround # https://github.com/pypa/packaging/commit/67c4a2820c549070bbfc4bfbf5e2a250075048da # # This results in packaging versions up to 21.3 generating # platform tags like "macosx_10_16_x86_64" and later versions # generating "macosx_11_0_x86_64". Using the latter would be more # correct but prevents the resulting wheel from being installed on # systems using packaging 21.3 or earlier (pip 22.3 or earlier). # # Fortunately packaging versions carrying the workaround still # accepts "macosx_10_16_x86_64" as a compatible platform tag. We # can therefore ignore the issue and generate the slightly # incorrect tag. major, minor = version if major >= 11: # For macOS reelases up to 10.15, the major version number is # actually part of the OS name and the minor version is the # actual OS release. Starting with macOS 11, the major # version number is the OS release and the minor version is # the patch level. Reset the patch level to zero. minor = 0 if _32_BIT_INTERPRETER: # 32-bit Python running on a 64-bit kernel. if arch == 'ppc64': arch = 'ppc' if arch == 'x86_64': arch = 'i386' return f'macosx_{major}_{minor}_{arch}' def get_platform_tag() -> str: platform = sysconfig.get_platform() if platform.startswith('macosx'): return _get_macosx_platform_tag() if _32_BIT_INTERPRETER: # 32-bit Python running on a 64-bit kernel. if platform == 'linux-x86_64': return 'linux_i686' if platform == 'linux-aarch64': return 'linux_armv7l' return platform.replace('-', '_').replace('.', '_').lower() class Tag: def __init__(self, interpreter: Optional[str] = None, abi: Optional[str] = None, platform: Optional[str] = None): self.interpreter = interpreter or get_interpreter_tag() self.abi = abi or get_abi_tag() self.platform = platform or get_platform_tag() def __str__(self) -> str: return f'{self.interpreter}-{self.abi}-{self.platform}' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/mesonpy/_util.py0000644000000000000000000000343514516424013014432 0ustar00# SPDX-FileCopyrightText: 2021 Filipe Laíns # SPDX-FileCopyrightText: 2021 Quansight, LLC # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import contextlib import gzip import itertools import os import sys import tarfile import typing from typing import IO if typing.TYPE_CHECKING: # pragma: no cover from typing import Any from mesonpy._compat import Iterator, Path, Self @contextlib.contextmanager def chdir(path: Path) -> Iterator[Path]: """Context manager helper to change the current working directory -- cd.""" old_cwd = os.getcwd() os.chdir(os.fspath(path)) try: yield path finally: os.chdir(old_cwd) @contextlib.contextmanager def create_targz(path: Path) -> Iterator[tarfile.TarFile]: """Opens a .tar.gz file in the file system for edition..""" os.makedirs(os.path.dirname(path), exist_ok=True) file = typing.cast(IO[bytes], gzip.GzipFile( path, mode='wb', )) tar = tarfile.TarFile( mode='w', fileobj=file, format=tarfile.PAX_FORMAT, # changed in 3.8 to GNU ) with contextlib.closing(file), tar: yield tar class clicounter: def __init__(self, total: int) -> None: self._total = total self._count = itertools.count(start=1) def __enter__(self) -> Self: return self def update(self, description: str) -> None: line = f'[{next(self._count)}/{self._total}] {description}' if sys.stdout.isatty(): print('\r', line, sep='', end='\33[0K', flush=True) else: print(line) def __exit__(self, exc_type: Any, exc_value: Any, exc_tb: Any) -> None: if sys.stdout.isatty(): print() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/mesonpy/_wheelfile.py0000644000000000000000000001030114516424013015407 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import base64 import csv import hashlib import io import os import re import stat import time import typing import zipfile if typing.TYPE_CHECKING: # pragma: no cover from types import TracebackType from typing import List, Optional, Tuple, Type, Union from mesonpy._compat import Path MIN_TIMESTAMP = 315532800 # 1980-01-01 00:00:00 UTC WHEEL_FILENAME_REGEX = re.compile(r'^(?P[^-]+)-(?P[^-]+)(:?-(?P[^-]+))?-(?P[^-]+-[^-]+-[^-]+).whl$') def _b64encode(data: bytes) -> bytes: return base64.urlsafe_b64encode(data).rstrip(b'=') class WheelFile: """Implement the wheel package binary distribution format. https://packaging.python.org/en/latest/specifications/binary-distribution-format/ """ def __new__(cls, filename: Path, mode: str = 'r', compression: int = zipfile.ZIP_DEFLATED) -> 'WheelFile': if mode == 'w': return super().__new__(WheelFileWriter) raise NotImplementedError @staticmethod def timestamp(mtime: Optional[float] = None) -> Tuple[int, int, int, int, int, int]: timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', mtime or time.time())) # The ZIP file format does not support timestamps before 1980. timestamp = max(timestamp, MIN_TIMESTAMP) return time.gmtime(timestamp)[0:6] @staticmethod def hash(data: bytes) -> str: return 'sha256=' + _b64encode(hashlib.sha256(data).digest()).decode('ascii') def writestr(self, zinfo_or_arcname: Union[str, zipfile.ZipInfo], data: bytes) -> None: raise NotImplementedError def write(self, filename: Path, arcname: Optional[str] = None) -> None: raise NotImplementedError def close(self) -> None: raise NotImplementedError def __enter__(self) -> WheelFile: return self def __exit__(self, exc_type: Type[BaseException], exc_val: BaseException, exc_tb: TracebackType) -> None: self.close() class WheelFileWriter(WheelFile): def __init__(self, filepath: Path, mode: str, compression: int = zipfile.ZIP_DEFLATED): filename = os.path.basename(filepath) match = WHEEL_FILENAME_REGEX.match(filename) if not match: raise ValueError(f'invalid wheel filename: {filename!r}') self.name = match.group('name') self.version = match.group('version') self.entries: List[Tuple[str, str, int]] = [] self.archive = zipfile.ZipFile(filepath, mode='w', compression=compression, allowZip64=True) def writestr(self, zinfo_or_arcname: Union[str, zipfile.ZipInfo], data: bytes) -> None: if isinstance(data, str): data = data.encode('utf-8') if isinstance(zinfo_or_arcname, zipfile.ZipInfo): zinfo = zinfo_or_arcname else: zinfo = zipfile.ZipInfo(zinfo_or_arcname, date_time=self.timestamp()) zinfo.external_attr = 0o664 << 16 self.archive.writestr( zinfo, data, compress_type=self.archive.compression, compresslevel=self.archive.compresslevel) self.entries.append((zinfo.filename, self.hash(data), len(data))) def write(self, filename: Path, arcname: Optional[str] = None) -> None: with open(filename, 'rb') as f: st = os.fstat(f.fileno()) data = f.read() zinfo = zipfile.ZipInfo(arcname or str(filename), date_time=self.timestamp(st.st_mtime)) zinfo.external_attr = (stat.S_IMODE(st.st_mode) | stat.S_IFMT(st.st_mode)) << 16 self.writestr(zinfo, data) def close(self) -> None: record = f'{self.name}-{self.version}.dist-info/RECORD' data = io.StringIO() writer = csv.writer(data, delimiter=',', quotechar='"', lineterminator='\n') writer.writerows(self.entries) writer.writerow((record, '', '')) zi = zipfile.ZipInfo(record, date_time=self.timestamp()) zi.external_attr = 0o664 << 16 self.archive.writestr( zi, data.getvalue(), compress_type=self.archive.compression, compresslevel=self.archive.compresslevel) self.archive.close() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/noxfile.py0000644000000000000000000000331514516424013013265 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import os import os.path import nox nox.options.sessions = ['docs', 'mypy', 'test'] nox.options.reuse_existing_virtualenvs = True @nox.session() def docs(session): """ Build the docs. Pass "serve" to serve. """ session.install('.[docs]') session.install('sphinx-autobuild') session.install('sphinxcontrib-spelling >= 7.0.0') session.chdir('docs') spelling_args = ('-b', 'spelling') sphinx_build_args = ('.', '_build') if not session.posargs: # run spell-checking session.run('sphinx-build', *spelling_args, *sphinx_build_args) # run normal build session.run('sphinx-build', *sphinx_build_args) else: if 'serve' in session.posargs: session.run('sphinx-autobuild', *sphinx_build_args) else: print('Unsupported argument to docs') @nox.session(python='3.7') def mypy(session): session.install('mypy==0.991') session.run('mypy', '-p', 'mesonpy') @nox.session(python=['3.7', '3.8', '3.9', '3.10', '3.11', 'pypy3.8', 'pypy3.9']) def test(session): htmlcov_output = os.path.join(session.virtualenv.location, 'htmlcov') xmlcov_output = os.path.join(session.virtualenv.location, f'coverage-{session.python}.xml') session.install('.[test]') # optional github actions integration if os.environ.get('GITHUB_ACTIONS') == 'true': session.install('pytest-github-actions-annotate-failures') session.run( 'pytest', '--showlocals', '-vv', '--cov', f'--cov-report=html:{htmlcov_output}', f'--cov-report=xml:{xmlcov_output}', *session.posargs ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/pyproject.toml0000644000000000000000000000524314516424013014165 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' backend-path = ['.'] requires = [ 'meson >= 0.63.3; python_version < "3.12"', 'meson >= 1.2.3; python_version >= "3.12"', 'pyproject-metadata >= 0.7.1', 'tomli >= 1.0.0; python_version < "3.11"', ] [project] name = 'meson-python' description = 'Meson Python build backend (PEP 517)' readme = 'README.rst' requires-python = '>= 3.7' license = { file = 'LICENSES/MIT.txt' } keywords = ['meson', 'build', 'backend', 'pep517', 'package'] maintainers = [ { name = 'Ralf Gommers ', email = 'ralf.gommers@gmail.com' }, { name = 'Daniele Nicolodi', email = 'daniele@grinta.net' }, { name = 'Henry Schreiner', email = 'HenrySchreinerIII@gmail.com' }, { name = 'Thomas Li'}, ] classifiers = [ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', 'Topic :: Software Development :: Build Tools', ] dependencies = [ 'colorama; os_name == "nt"', 'meson >= 0.63.3; python_version < "3.12"', 'meson >= 1.2.3; python_version >= "3.12"', 'pyproject-metadata >= 0.7.1', 'tomli >= 1.0.0; python_version < "3.11"', ] dynamic = [ 'version', ] [project.optional-dependencies] test = [ 'build', 'pytest >= 6.0', 'pytest-cov[toml]', 'pytest-mock', 'cython >= 3.0.3', # required for Python 3.12 support 'wheel', 'typing-extensions >= 3.7.4; python_version < "3.11"', ] docs = [ 'furo >= 2021.08.31', 'sphinx ~= 4.0', 'sphinx-copybutton >= 0.5.0', 'sphinx-design >= 0.1.0', 'sphinxext-opengraph >= 0.7.0', ] [project.urls] homepage = 'https://github.com/mesonbuild/meson-python' repository = 'https://github.com/mesonbuild/meson-python' documentation = 'https://meson-python.readthedocs.io/' changelog = 'https://meson-python.readthedocs.io/en/latest/changelog.html' [tool.mypy] show_error_codes = true ignore_missing_imports = true strict = true [tool.ruff] line-length = 127 extend-ignore = [ 'B019', ] select = [ 'B', # flake8-bugbear 'C4', # flake8-comprehensions 'E', # pycodestyle 'F', # pyflakes 'W', # pycodestyle 'RUF100', # ruff ] exclude = [ 'docs/conf.py', ] [tool.isort] lines_between_types = 1 lines_after_imports = 2 multi_line_output = 5 known_first_party = 'mesonpy' line_length = 127 skip = [ 'docs/conf.py', ] [tool.coverage.run] disable_warnings = [ 'couldnt-parse', ] [tool.coverage.html] show_contexts = true [tool.pytest.ini_options] minversion = '6.0' addopts = ['-ra', '--strict-markers', '--strict-config'] log_cli_level = 'info' norecursedirs = 'tests/packages/*' testpaths = ['tests'] xfail_strict = true filterwarnings = [ 'error', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/__init__.py0000644000000000000000000000013414516424013014516 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/conftest.py0000644000000000000000000001302614516424013014610 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import contextlib import os import os.path import pathlib import re import shutil import subprocess import sys import tempfile import warnings from venv import EnvBuilder import pytest import mesonpy from mesonpy._util import chdir def adjust_packaging_platform_tag(platform: str) -> str: if platform.startswith(('manylinux', 'musllinux')): # The packaging module generates overly specific platforms tags on # Linux. The platforms tags on Linux evolved over time. # meson-python uses more relaxed platform tags to maintain # compatibility with old wheel installation tools. The relaxed # platform tags match the ones generated by the wheel package. # https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/ return re.sub(r'^(many|musl)linux(1|2010|2014|_\d+_\d+)_(.*)$', r'linux_\3', platform) if platform.startswith('macosx'): # Python built with older macOS SDK on macOS 11, reports an # unexising macOS 10.16 version instead of the real version. # The packaging module introduced a workaround in version # 22.0. Too maintain compatibility with older packaging # releases we don't implement it. Reconcile this. from platform import mac_ver version = tuple(map(int, mac_ver()[0].split('.')))[:2] if version == (10, 16): return re.sub(r'^macosx_\d+_\d+_(.*)$', r'macosx_10_16_\1', platform) return platform package_dir = pathlib.Path(__file__).parent / 'packages' @contextlib.contextmanager def in_git_repo_context(path=os.path.curdir): # Resist the tentation of using pathlib.Path here: it is not # supporded by subprocess in Python 3.7. path = os.path.abspath(path) shutil.rmtree(os.path.join(path, '.git'), ignore_errors=True) try: subprocess.run(['git', 'init', '-b', 'main', path], check=True) subprocess.run(['git', 'config', 'user.email', 'author@example.com'], cwd=path, check=True) subprocess.run(['git', 'config', 'user.name', 'A U Thor'], cwd=path, check=True) subprocess.run(['git', 'add', '*'], cwd=path, check=True) subprocess.run(['git', 'commit', '-q', '-m', 'Test'], cwd=path, check=True) yield finally: # PermissionError raised on Windows. with contextlib.suppress(PermissionError): shutil.rmtree(os.path.join(path, '.git')) @pytest.fixture(scope='session') def tmp_path_session(tmp_path_factory): return pathlib.Path(tempfile.mkdtemp( prefix='mesonpy-test-', dir=tmp_path_factory.mktemp('test'), )) class VEnv(EnvBuilder): def __init__(self, env_dir): super().__init__(symlinks=True, with_pip=True) # This warning is mistakenly generated by CPython 3.11.0 # https://github.com/python/cpython/pull/98743 with warnings.catch_warnings(): if sys.version_info[:3] == (3, 11, 0): warnings.filterwarnings('ignore', 'check_home argument is deprecated and ignored.', DeprecationWarning) self.create(env_dir) def ensure_directories(self, env_dir): context = super().ensure_directories(env_dir) # Store the path to the venv Python interpreter. There does # not seem to be a way to do this without subclassing. self.executable = context.env_exe return context def python(self, *args: str): return subprocess.check_output([self.executable, *args]).decode() def pip(self, *args: str): return self.python('-m', 'pip', *args) @pytest.fixture() def venv(tmp_path_factory): path = pathlib.Path(tmp_path_factory.mktemp('mesonpy-test-venv')) return VEnv(path) def generate_package_fixture(package): @pytest.fixture def fixture(): with chdir(package_dir / package) as new_path: yield new_path return fixture def generate_sdist_fixture(package): @pytest.fixture(scope='session') def fixture(tmp_path_session): with chdir(package_dir / package), in_git_repo_context(): return tmp_path_session / mesonpy.build_sdist(tmp_path_session) return fixture def generate_wheel_fixture(package): @pytest.fixture(scope='session') def fixture(tmp_path_session): with chdir(package_dir / package), in_git_repo_context(): return tmp_path_session / mesonpy.build_wheel(tmp_path_session) return fixture def generate_editable_fixture(package): @pytest.fixture(scope='session') def fixture(tmp_path_session): shutil.rmtree(package_dir / package / '.mesonpy' / 'editable', ignore_errors=True) with chdir(package_dir / package), in_git_repo_context(): return tmp_path_session / mesonpy.build_editable(tmp_path_session) return fixture # inject {package,sdist,wheel}_* fixtures (https://github.com/pytest-dev/pytest/issues/2424) for package in os.listdir(package_dir): normalized = package.replace('-', '_') globals()[f'package_{normalized}'] = generate_package_fixture(package) globals()[f'sdist_{normalized}'] = generate_sdist_fixture(package) globals()[f'wheel_{normalized}'] = generate_wheel_fixture(package) globals()[f'editable_{normalized}'] = generate_editable_fixture(package) @pytest.fixture(autouse=True, scope='session') def disable_pip_version_check(): # Cannot use the 'monkeypatch' fixture because of scope mismatch. mpatch = pytest.MonkeyPatch() yield mpatch.setenv('PIP_DISABLE_PIP_VERSION_CHECK', '1') mpatch.undo() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/complex/complex/__init__.py0000644000000000000000000000013414516424013021412 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/complex/complex/more/__init__.py0000644000000000000000000000016714516424013022362 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def test(): return 44 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/complex/complex/namespace/bar.py0000644000000000000000000000017114516424013022354 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def bar(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/complex/complex/namespace/foo.py0000644000000000000000000000017114516424013022373 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'foo' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/complex/meson.build0000644000000000000000000000131714516424013020000 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('complex', 'c', 'cython', version: '1.0.0') # Work around Python bug on mingw-w64, fixed in Python 3.12 # https://github.com/python/cpython/pull/100137 # The same work-around is also included in Meson 1.1.0 and later. if meson.version().version_compare('< 1.1') if host_machine.system() == 'windows' and meson.get_compiler('c').get_id() == 'gcc' add_project_arguments('-DMS_WIN64=', language: 'c') endif endif py = import('python').find_installation() install_subdir('complex', install_dir: py.get_install_dir(pure: false)) py.extension_module('test', 'test.pyx', install: true, subdir: 'complex') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/complex/pyproject.toml0000644000000000000000000000024214516424013020546 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/complex/test.pyx0000644000000000000000000000017114516424013017354 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def answer(): return 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/configure-data/configure_data.py.in0000644000000000000000000000021314516424013023002 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def message(): return 'meson says: @MSG@' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/configure-data/meson.build0000644000000000000000000000055414516424013021223 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('configure-data', version: '1.0.0') py = import('python').find_installation() configure_file( input: 'configure_data.py.in', output: 'configure_data.py', configuration: configuration_data({'MSG': 'hello!'}), install_dir: py.get_install_dir(), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/configure-data/pyproject.toml0000644000000000000000000000024214516424013021767 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/detect-compiler/detect_compiler.c0000644000000000000000000000133414516424013022554 0ustar00// SPDX-FileCopyrightText: 2023 The meson-python developers // // SPDX-License-Identifier: MIT #include #if defined _MSC_VER # define _COMPILER "msvc" #elif defined __clang__ # define _COMPILER "clang" #elif defined __GNUC__ # define _COMPILER "gcc" #else # define _COMPILER "unknown" #endif static PyObject* compiler(PyObject* self) { return PyUnicode_FromString(_COMPILER); } static PyMethodDef methods[] = { {"compiler", (PyCFunction)compiler, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "detect_compiler", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_detect_compiler(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/detect-compiler/meson.build0000644000000000000000000000040414516424013021405 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('detect-compiler', 'c', version: '1.0') py = import('python').find_installation() py.extension_module('detect_compiler', 'detect_compiler.c', install: true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/detect-compiler/pyproject.toml0000644000000000000000000000024214516424013022157 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/dist-script/meson.build0000644000000000000000000000024614516424013020576 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('dist-script', 'c', version: '1.0.0') meson.add_dist_script('') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/dist-script/pyproject.toml0000644000000000000000000000024214516424013021344 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/dynamic-version/meson.build0000644000000000000000000000021214516424013021431 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('dynamic-version', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/dynamic-version/pyproject.toml0000644000000000000000000000034314516424013022210 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'dynamic-version' dynamic = [ 'version', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/executable/example.c0000644000000000000000000000022614516424013020105 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include int main() { printf("hello!"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/executable/meson.build0000644000000000000000000000031414516424013020446 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('executable', 'c', version: '1.0.0') executable( 'example', 'example.c', install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/executable/pyproject.toml0000644000000000000000000000024214516424013021220 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/executable-bit/example-script.py0000755000000000000000000000016714516424013022400 0ustar00#!python # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT print('hello!') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/executable-bit/example.c0000644000000000000000000000022614516424013020661 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include int main() { printf("hello!"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/executable-bit/executable_module.py0000755000000000000000000000025714516424013023131 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' if __name__ == '__main__': print('foo?', foo()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/executable-bit/meson.build0000644000000000000000000000062614516424013021230 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('executable-bit', 'c', version: '1.0.0') py = import('python').find_installation() executable( 'example', 'example.c', install: true, ) install_data( 'example-script.py', rename: 'example-script', install_dir: get_option('bindir'), ) py.install_sources('executable_module.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/executable-bit/pyproject.toml0000644000000000000000000000024214516424013021774 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/full-metadata/LICENSE0000644000000000000000000000001514516424013017706 0ustar00some license ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/full-metadata/README.md0000644000000000000000000000024714516424013020167 0ustar00 # full-metadata An example package with all of the PEP 621 metadata! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/full-metadata/meson.build0000644000000000000000000000021014516424013021040 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('full-metadata', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/full-metadata/pyproject.toml0000644000000000000000000000217614516424013021627 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'full-metadata' version = '1.2.3' description = 'Some package with all of the PEP 621 metadata' readme = 'README.md' requires-python = '>=3.7' license = {file = 'LICENSE'} keywords = ['full', 'metadata'] authors = [ {email = 'jhon.doe@example.com'}, {name = 'Jane Doe'} ] maintainers = [ {name = 'Jane Doe', email = 'jane.doe@example.com'} ] classifiers = [ 'Development Status :: 4 - Beta', 'Programming Language :: Python', ] dependencies = [ 'a', 'b > 1', 'c > 2; os_name != "nt"', ] [project.optional-dependencies] test = [ 'd < 3', 'e[all]' ] [project.urls] homepage = 'https://example.com' documentation = 'https://readthedocs.org' repository = 'https://github.com/mesonbuild/meson-python' changelog = 'https://github.com/mesonbuild/meson-python/blob/master/CHANGELOG.rst' [project.scripts] example-cli = 'example:cli' [project.gui-scripts] example-gui = 'example:gui' [project.entry-points.'something.custom'] example = 'example:custom' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/generated-files/example-script.py0000755000000000000000000000016714516424013022541 0ustar00#!python # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT print('hello!') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/generated-files/example.c0000644000000000000000000000022614516424013021022 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include int main() { printf("hello!"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/generated-files/executable_module.py0000755000000000000000000000025714516424013023272 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' if __name__ == '__main__': print('foo?', foo()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/generated-files/generate_version.py0000644000000000000000000000171014516424013023133 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT import argparse import os def write_version_info(path): # A real project would call something to generate this dummy_version = '1.0.0' dummy_hash = '013j2fiejqea' if os.environ.get('MESON_DIST_ROOT'): path = os.path.join(os.environ.get('MESON_DIST_ROOT'), path) with open(path, 'w') as file: file.write(f'__version__="{dummy_version}"\n') file.write( f'__git_version__="{dummy_hash}"\n' ) def main(): parser = argparse.ArgumentParser() parser.add_argument( '-o', '--outfile', type=str, help='Path to write version info to' ) args = parser.parse_args() if not args.outfile.endswith('.py'): raise ValueError( f'Output file must be a Python file. ' f'Got: {args.outfile} as filename instead' ) write_version_info(args.outfile) main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/generated-files/meson.build0000644000000000000000000000162514516424013021371 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('executable-bit', 'c', version: '1.0.0') fs = import('fs') py = import('python').find_installation() executable( 'example', 'example.c', install: true, ) install_data( 'example-script.py', rename: 'example-script', install_dir: get_option('bindir'), ) py.install_sources('executable_module.py') version_gen = files('generate_version.py') if fs.exists('_version_meson.py') py.install_sources('_version_meson.py') else custom_target( 'write_version_file', output: '_version_meson.py', command: [py, version_gen, '-o', '@OUTPUT@'], build_by_default: true, build_always_stale: true, install: true, install_dir: py.get_install_dir(pure: false), ) meson.add_dist_script(py, version_gen, '-o', '_version_meson.py') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/generated-files/pyproject.toml0000644000000000000000000000024214516424013022135 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/imports-itself-during-build/meson.build0000644000000000000000000000051714516424013023676 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('imports-itself-during-build', 'c', version: '1.0.0') py = import('python').find_installation() py.install_sources('pure.py') py.extension_module( 'plat', 'plat.c', install: true, ) run_command(py, '-c', 'import pure') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/imports-itself-during-build/plat.c0000644000000000000000000000076514516424013022645 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* data(PyObject* self) { return PyUnicode_FromString("ABC"); } static PyMethodDef methods[] = { {"data", (PyCFunction)data, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "plat", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_plat(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/imports-itself-during-build/pure.py0000644000000000000000000000017114516424013023055 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/imports-itself-during-build/pyproject.toml0000644000000000000000000000024214516424013024443 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/meson.build0000644000000000000000000000111214516424013021256 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('install-subdir', version: '1.0.0') py = import('python').find_installation() install_subdir( 'subdir', exclude_files: 'excluded.py', exclude_directories: 'excluded', install_dir: py.get_install_dir(pure: false), ) install_subdir( 'strip', strip_directory: true, exclude_files: 'excluded.py', install_dir: py.get_install_dir(pure: false) / 'test', ) install_subdir( 'nested', exclude_files: 'deep/excluded.py', install_dir: py.get_install_dir(pure: false), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/nested/deep/deep.py0000644000000000000000000000013414516424013022605 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/nested/deep/excluded.py0000644000000000000000000000013414516424013023465 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/nested/nested.py0000644000000000000000000000013414516424013022235 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/pyproject.toml0000644000000000000000000000024214516424013022033 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/strip/excluded.py0000644000000000000000000000013414516424013022427 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/strip/module.py0000644000000000000000000000013414516424013022117 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/subdir/__init__.py0000644000000000000000000000013414516424013022520 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/subdir/excluded/__init__.py0000644000000000000000000000013414516424013024315 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/subdir/excluded.py0000644000000000000000000000013414516424013022556 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/install-subdir/subdir/test.py0000644000000000000000000000013414516424013021740 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/library/example.c0000644000000000000000000000026614516424013017434 0ustar00// SPDX-FileCopyrightText: 2021 The meson-python developers // // SPDX-License-Identifier: MIT #include int sum(int, int); int main() { printf("sum: %d", sum(1, 2)); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/library/examplelib.c0000644000000000000000000000021114516424013020111 0ustar00// SPDX-FileCopyrightText: 2021 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b) { return a + b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/library/examplelib.h0000644000000000000000000000016714516424013020130 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/library/meson.build0000644000000000000000000000053514516424013017776 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('library', 'c', version: '1.0.0') install_headers('examplelib.h') example_lib = shared_library( 'example', 'examplelib.c', install: true, ) executable( 'example', 'example.c', link_with: example_lib, install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/library/pyproject.toml0000644000000000000000000000024214516424013020543 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/license-file/meson.build0000644000000000000000000000020714516424013020665 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('license-file', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/license-file/pyproject.toml0000644000000000000000000000040514516424013021437 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'license-file' version = '1.0.0' license = { file = 'something/LICENSE.custom' } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/license-file/something/LICENSE.custom0000644000000000000000000000000714516424013023034 0ustar00Hello! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/limited-api/meson.build0000644000000000000000000000060314516424013020524 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('limited-api', 'c', version: '1.0.0') py = import('python').find_installation(pure: false) py.extension_module( 'module', 'module.c', limited_api: '3.7', install: true, ) if get_option('extra') py.extension_module( 'extra', 'module.c', install: true, ) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/limited-api/meson.options0000644000000000000000000000021414516424013021116 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT option('extra', type: 'boolean', value: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/limited-api/module.c0000644000000000000000000000110714516424013020013 0ustar00// SPDX-FileCopyrightText: 2023 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* add(PyObject *self, PyObject *args) { int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) return NULL; return PyLong_FromLong(a + b); } static PyMethodDef methods[] = { {"add", add, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "plat", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_module(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/limited-api/pyproject.toml0000644000000000000000000000031214516424013021273 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python] limited-api = true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/link-against-local-lib/examplemod.c0000644000000000000000000000126314516424013022703 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include #include "lib/examplelib.h" static PyObject* example_sum(PyObject* self, PyObject *args) { int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) { return NULL; } long result = sum(a, b); return PyLong_FromLong(result); } static PyMethodDef methods[] = { {"example_sum", (PyCFunction)example_sum, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "example", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_example(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/link-against-local-lib/lib/examplelib.c0000644000000000000000000000021114516424013023430 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b) { return a + b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/link-against-local-lib/lib/examplelib.h0000644000000000000000000000016714516424013023447 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/link-against-local-lib/lib/meson.build0000644000000000000000000000026314516424013023313 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT example_lib = shared_library( 'example', 'examplelib.c', install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/link-against-local-lib/meson.build0000644000000000000000000000054614516424013022551 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('link-against-local-lib', 'c', version: '1.0.0') subdir('lib') py = import('python').find_installation() py.extension_module( 'example', 'examplemod.c', link_with: example_lib, link_args: ['-Wl,-rpath,custom-rpath'], install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/link-against-local-lib/pyproject.toml0000644000000000000000000000024214516424013023314 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/missing-dynamic-version/meson.build0000644000000000000000000000020014516424013023075 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('missing-dynamic-version') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/missing-dynamic-version/pyproject.toml0000644000000000000000000000034414516424013023660 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'missing-dynamic-version' dynamic = ['version'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/missing-meson-version/meson.build0000644000000000000000000000017614516424013022606 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('missing-meson-version') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/missing-meson-version/pyproject.toml0000644000000000000000000000024214516424013023352 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/missing-version/meson.build0000644000000000000000000000021214516424013021456 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('missing-version', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/missing-version/pyproject.toml0000644000000000000000000000030614516424013022234 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'missing-version' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/module-types/file.py0000644000000000000000000000013414516424013020103 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/module-types/meson.build0000644000000000000000000000066614516424013020766 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('module-types', 'c', version: '1.0.0') py = import('python').find_installation() py.install_sources('file.py') py.install_sources( 'package' / '__init__.py', subdir: 'package', ) py.install_sources( 'namespace' / 'data.py', subdir: 'namespace', ) py.extension_module( 'native', 'native.c', install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/module-types/namespace/data.py0000644000000000000000000000013414516424013022031 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/module-types/native.c0000644000000000000000000000076614516424013020257 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* foo(PyObject* self) { return PyUnicode_FromString("bar"); } static PyMethodDef methods[] = { {"foo", (PyCFunction)foo, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "native", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_native(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/module-types/package/__init__.py0000644000000000000000000000013414516424013022316 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/module-types/pyproject.toml0000644000000000000000000000024214516424013021526 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/pure/meson.build0000644000000000000000000000031114516424013017275 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('pure', version: '1.0.0') py = import('python').find_installation() py.install_sources('pure.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/pure/pure.py0000644000000000000000000000017114516424013016464 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/pure/pyproject.toml0000644000000000000000000000024214516424013020052 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/purelib-and-platlib/meson.build0000644000000000000000000000054114516424013022156 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('purelib-and-platlib', 'c', version: '1.0.0') py = import('python').find_installation() py.install_sources( 'pure.py', install_tag: 'purelib', ) py.extension_module( 'plat', 'plat.c', install: true, install_tag: 'platlib', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/purelib-and-platlib/plat.c0000644000000000000000000000076214516424013021125 0ustar00// SPDX-FileCopyrightText: 2021 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* foo(PyObject* self) { return PyUnicode_FromString("bar"); } static PyMethodDef methods[] = { {"foo", (PyCFunction)foo, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "plat", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_plat(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/purelib-and-platlib/pure.py0000644000000000000000000000017114516424013021340 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/purelib-and-platlib/pyproject.toml0000644000000000000000000000024214516424013022726 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/purelib-platlib-split/meson.build0000644000000000000000000000054214516424013022550 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('purelib-platlib-split', version: '1.0.0') py = import('python').find_installation() py.install_sources( 'pure.py', subdir: 'purelib-platlib-split', ) py.install_sources( 'plat.py', subdir: 'purelib-platlib-split', pure: false, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/purelib-platlib-split/plat.py0000644000000000000000000000017114516424013021716 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/purelib-platlib-split/pure.py0000644000000000000000000000017114516424013021731 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/purelib-platlib-split/pyproject.toml0000644000000000000000000000024214516424013023317 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/scipy-like/meson.build0000644000000000000000000000111714516424013020400 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('scipy-like', 'c', 'cython', version: '2.3.4') # Work around Python bug on mingw-w64, fixed in Python 3.12 # https://github.com/python/cpython/pull/100137 # The same work-around is also included in Meson 1.1.0 and later. if meson.version().version_compare('< 1.1') if host_machine.system() == 'windows' and meson.get_compiler('c').get_id() == 'gcc' add_project_arguments('-DMS_WIN64=', language: 'c') endif endif py = import('python').find_installation() subdir('mypkg') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/scipy-like/mypkg/__init__.py0000644000000000000000000000017114516424013021475 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/scipy-like/mypkg/cy_extmod.pyx0000644000000000000000000000025114516424013022120 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from libc.math cimport sin cdef double f(double x): return sin(x * x) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/scipy-like/mypkg/extmod.c0000644000000000000000000000076414516424013021040 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* foo(PyObject* self) { return PyUnicode_FromString("bar"); } static PyMethodDef methods[] = { {"foo", (PyCFunction)foo, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "extmod", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_plat(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/scipy-like/mypkg/meson.build0000644000000000000000000000153014516424013021526 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT generate_version = custom_target( 'generate-config-file', install: true, build_always_stale: true, build_by_default: true, output: '__config__.py', input: '../tools/generate_config.py', command: [py, '@INPUT@', '@OUTPUT@'], install_dir: py.get_install_dir(pure: false) / 'mypkg', ) py.extension_module( 'extmod', 'extmod.c', install: true, subdir: 'mypkg', ) py.extension_module( 'cy_extmod', 'cy_extmod.pyx', install: true, subdir: 'mypkg', ) py.install_sources( '__init__.py', pure: false, subdir: 'mypkg', ) # Still broken, see gh-105 and https://github.com/mesonbuild/meson/issues/10639 install_subdir( 'submod', install_dir: py.get_install_dir(pure: false) / 'mypkg', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/scipy-like/mypkg/submod/__init__.py0000644000000000000000000000013414516424013022765 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/scipy-like/mypkg/submod/unknown_filetype.npq0000644000000000000000000000027314516424013025000 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # Unknown file types (e.g. `.npy` or `.npz` data files) can be present in # a Python package. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/scipy-like/pyproject.toml0000644000000000000000000000040214516424013021146 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = "mypkg" description = "A typical Python package layout" dynamic = ['version'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/scipy-like/tools/generate_config.py0000644000000000000000000000033314516424013023066 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT import sys from pathlib import Path outfile = Path(sys.argv[1]) outfile.write_text('# Some build-time configuration data') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/simple/__init__.py0000644000000000000000000000020214516424013017561 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT from .test import data # noqa: F401 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/simple/data.txt0000644000000000000000000000000414516424013017122 0ustar00ABC ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/simple/data.txt.license0000644000000000000000000000013414516424013020547 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/simple/meson.build0000644000000000000000000000037014516424013017620 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('simple', version: '1.0.0') py = import('python').find_installation() py.install_sources('__init__.py', 'test.py', 'data.txt', subdir: 'simple') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/simple/pyproject.toml0000644000000000000000000000024214516424013020370 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/simple/test.py0000644000000000000000000000034414516424013017010 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib def data(): with pathlib.Path(__file__).parent.joinpath('data.txt').open() as f: return f.read().rstrip() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subdirs/meson.build0000644000000000000000000000111214516424013017775 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('subdirs', version: '1.0.0') py = import('python').find_installation() # in Meson >= 0.64 this could be replace with a single # py.install_sources() with the 'preserve_path: true' argument. py.install_sources( 'subdirs/__init__.py', subdir: 'subdirs', ) py.install_sources( 'subdirs/a/__init__.py', subdir: 'subdirs/a', ) py.install_sources( 'subdirs/a/b/c.py', subdir: 'subdirs/a/b', ) py.install_sources( 'subdirs/b/c.py', subdir: 'subdirs/b', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subdirs/pyproject.toml0000644000000000000000000000024214516424013020552 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subdirs/subdirs/__init__.py0000644000000000000000000000013414516424013021422 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subdirs/subdirs/a/__init__.py0000644000000000000000000000013414516424013021642 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subdirs/subdirs/a/b/c.py0000644000000000000000000000013414516424013020546 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subdirs/subdirs/b/c.py0000644000000000000000000000013414516424013020326 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subproject/meson.build0000644000000000000000000000035014516424013020505 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('subproject', version: '1.0.0') subproject('dep') py = import('python').find_installation() py.install_sources('subproject.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subproject/pyproject.toml0000644000000000000000000000024214516424013021257 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subproject/subproject.py0000644000000000000000000000013414516424013021075 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subproject/subprojects/dep/dep.py0000644000000000000000000000013414516424013022600 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/subproject/subprojects/dep/meson.build0000644000000000000000000000026514516424013023625 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('dep') py = import('python').find_installation() py.install_sources('dep.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/unknown-user-args-meson-args/pyproject.toml0000644000000000000000000000031114516424013024552 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python.args] unknown = [] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/unknown-user-args-top-level/pyproject.toml0000644000000000000000000000030414516424013024410 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python] unknown = {} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/unsupported-python-version/meson.build0000644000000000000000000000022514516424013023720 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('unsupported-python-version', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/unsupported-python-version/pyproject.toml0000644000000000000000000000037714516424013024502 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'unsupported-python-version' version = '1.2.3' requires-python = '==1.0.0' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/user-args/meson.build0000644000000000000000000000031614516424013020237 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('user-args', version: '1.0.0') py = import('python').find_installation() py.install_sources('pure.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/user-args/pure.py0000644000000000000000000000017114516424013017421 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/user-args/pyproject.toml0000644000000000000000000000044614516424013021015 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python.args] dist = ['config-dist'] setup = ['config-setup'] compile = ['config-compile'] install = ['config-install'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/vendored-meson/meson.build0000644000000000000000000000044514516424013021257 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('vendored-meson', version: '1.0.0') py = import('python').find_installation() if not get_option('custom-meson-used') error('Expected option "custom-meson-used" was not specified') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/vendored-meson/meson_options.txt0000644000000000000000000000023014516424013022542 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT option('custom-meson-used', type: 'boolean', value: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/vendored-meson/pyproject.toml0000644000000000000000000000032614516424013022027 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python] meson = 'third-party/meson.py' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/packages/vendored-meson/third-party/meson.py0000644000000000000000000000042014516424013023050 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT import sys from mesonbuild import mesonmain if 'setup' in sys.argv: sys.argv.append('-Dcustom-meson-used=true') if __name__ == '__main__': sys.exit(mesonmain.main()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_consistency.py0000644000000000000000000000135414516424013016364 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib import sys if sys.version_info >= (3, 11): import tomllib else: import tomli as tomllib def test_pyproject_dependencies(): pyproject = pathlib.Path(__file__).parent.parent.joinpath('pyproject.toml') with open(pyproject, 'rb') as f: data = tomllib.load(f) build_dependencies = data['build-system']['requires'] project_dependencies = data['project']['dependencies'] # verify that all build dependencies are project dependencies assert not set(build_dependencies) - set(project_dependencies), \ 'pyproject.toml is inconsistent: not all "build-system.requires" are in "project.dependencies"' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_editable.py0000644000000000000000000001664314516424013015603 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import os import pathlib import sys import pytest import mesonpy from mesonpy import _editable from .test_wheel import EXT_SUFFIX def test_walk(package_complex): entries = set(_editable.walk(os.fspath(package_complex / 'complex'))) assert entries == { pathlib.Path('__init__.py'), pathlib.Path('more/__init__.py'), pathlib.Path('namespace/bar.py'), pathlib.Path('namespace/foo.py') } def test_nodes_tree(): tree = _editable.Node() tree[('aa', 'bb', 'cc')] = 'path1' tree[('aa', 'dd')] = 'path2' assert tree['aa']['bb']['cc'] == 'path1' assert tree['aa']['dd'] == 'path2' assert tree[('aa', 'bb', 'cc')] == 'path1' assert tree.get(('aa', 'bb', 'cc')) == 'path1' assert tree['aa'] == tree[('aa', )] assert tree.get(('aa', 'gg')) is None assert tree[('aa', 'gg')] == _editable.Node() def test_collect(package_complex): root = os.fspath(package_complex) install_plan = { 'targets': { os.path.join(root, 'build', f'test{EXT_SUFFIX}'): { 'destination': os.path.join('{py_platlib}', 'complex', f'test{EXT_SUFFIX}'), 'tag': 'runtime'}, }, 'install_subdirs': { os.path.join(root, 'complex'): { 'destination': os.path.join('{py_platlib}', 'complex'), 'tag': None} } } tree = _editable.collect(install_plan) assert tree['complex']['__init__.py'] == os.path.join(root, 'complex', '__init__.py') assert tree['complex'][f'test{EXT_SUFFIX}'] == os.path.join(root, 'build', f'test{EXT_SUFFIX}') assert tree['complex']['more']['__init__.py'] == os.path.join(root, 'complex', 'more', '__init__.py') def test_mesonpy_meta_finder(package_complex, tmp_path): # build a package in a temporary directory mesonpy.Project(package_complex, tmp_path) # point the meta finder to the build directory finder = _editable.MesonpyMetaFinder({'complex'}, os.fspath(tmp_path), ['ninja']) # check repr assert repr(finder) == f'MesonpyMetaFinder({str(tmp_path)!r})' # verify that we can look up a pure module in the source directory spec = finder.find_spec('complex') assert spec.name == 'complex' assert isinstance(spec.loader, _editable.SourceFileLoader) assert spec.origin == os.fspath(package_complex / 'complex/__init__.py') # and an extension module in the build directory spec = finder.find_spec('complex.test') assert spec.name == 'complex.test' assert isinstance(spec.loader, _editable.ExtensionFileLoader) assert spec.origin == os.fspath(tmp_path / f'test{EXT_SUFFIX}') try: # install the finder in the meta path sys.meta_path.insert(0, finder) # verify that we can import the modules import complex assert complex.__spec__.origin == os.fspath(package_complex / 'complex/__init__.py') assert complex.__file__ == os.fspath(package_complex / 'complex/__init__.py') import complex.test assert complex.test.__spec__.origin == os.fspath(tmp_path / f'test{EXT_SUFFIX}') assert complex.test.answer() == 42 import complex.namespace.foo assert complex.namespace.foo.__spec__.origin == os.fspath(package_complex / 'complex/namespace/foo.py') assert complex.namespace.foo.foo() == 'foo' finally: # remove finder from the meta path del sys.meta_path[0] def test_mesonpy_traversable(): tree = _editable.Node() tree[('package', '__init__.py')] = '/tmp/src/package/__init__.py' tree[('package', 'src.py')] = '/tmp/src/package/src.py' tree[('package', 'data.txt')] = '/tmp/src/package/data.txt' tree[('package', 'nested', '__init__.py')] = '/tmp/src/package/nested/__init__.py' tree[('package', 'nested', 'some.py')] = '/tmp/src/package/nested/some.py' tree[('package', 'nested', 'generated.txt')] = '/tmp/build/generated.txt' traversable = _editable.MesonpyTraversable('package', tree['package']) assert {x.name for x in traversable.iterdir()} == {'__init__.py', 'src.py', 'data.txt', 'nested'} nested = traversable / 'nested' assert nested.is_dir() assert {x.name for x in nested.iterdir()} == {'__init__.py', 'some.py', 'generated.txt'} generated = traversable.joinpath('nested', 'generated.txt') assert isinstance(generated, pathlib.Path) assert generated == pathlib.Path('/tmp/build/generated.txt') bad = traversable / 'bad' assert not bad.is_file() assert not bad.is_dir() with pytest.raises(FileNotFoundError): bad.open() def test_resources(tmp_path): # build a package in a temporary directory package_path = pathlib.Path(__file__).parent / 'packages' / 'simple' mesonpy.Project(package_path, tmp_path) # point the meta finder to the build directory finder = _editable.MesonpyMetaFinder({'simple'}, os.fspath(tmp_path), ['ninja']) # verify that we can look up resources spec = finder.find_spec('simple') reader = spec.loader.get_resource_reader('simple') traversable = reader.files() assert {x.name for x in traversable.iterdir()} == {'__init__.py', 'test.py', 'data.txt'} with traversable.joinpath('data.txt').open() as f: text = f.read().rstrip() assert text == 'ABC' @pytest.mark.skipif(sys.version_info < (3, 9), reason='importlib.resources not available') def test_importlib_resources(tmp_path): # build a package in a temporary directory package_path = pathlib.Path(__file__).parent / 'packages' / 'simple' mesonpy.Project(package_path, tmp_path) # point the meta finder to the build directory finder = _editable.MesonpyMetaFinder({'simple'}, os.fspath(tmp_path), ['ninja']) try: # install the finder in the meta path sys.meta_path.insert(0, finder) # verify that we can import the modules import simple assert simple.__spec__.origin == os.fspath(package_path / '__init__.py') assert simple.__file__ == os.fspath(package_path / '__init__.py') assert simple.data() == 'ABC' # load resources via importlib import importlib.resources with importlib.resources.files(simple).joinpath('data.txt').open() as f: text = f.read().rstrip() assert text == 'ABC' assert importlib.resources.files(simple).joinpath('data.txt').read_text().rstrip() == 'ABC' finally: # remove finder from the meta path del sys.meta_path[0] def test_editable_install(venv, editable_simple): venv.pip('install', os.fspath(editable_simple)) assert venv.python('-c', 'import simple; print(simple.data())').strip() == 'ABC' def test_editble_reentrant(venv, editable_imports_itself_during_build): venv.pip('install', os.fspath(editable_imports_itself_during_build)) assert venv.python('-c', 'import plat; print(plat.data())').strip() == 'ABC' path = pathlib.Path(__file__).parent / 'packages' / 'imports-itself-during-build' / 'plat.c' code = path.read_text() try: # edit souce code path.write_text(code.replace('ABC', 'DEF')) # check that the module is rebuilt on import. the build proess # imports python code from the source directory, thus this # test also check that this import does not cause an rebuild # loop assert venv.python('-c', 'import plat; print(plat.data())').strip() == 'DEF' finally: path.write_text(code) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_examples.py0000644000000000000000000000177114516424013015644 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib import subprocess import sys import pytest import mesonpy from mesonpy._util import chdir examples_dir = pathlib.Path(__file__).parent.parent / 'docs' / 'examples' def test_spam(venv, tmp_path): """Test that the wheel for the example builds, installs, and imports.""" with chdir(examples_dir / 'spam'): if sys.version_info < (3, 8): # The test project requires Python >= 3.8. with pytest.raises(SystemExit): mesonpy.build_wheel(tmp_path) else: wheel = mesonpy.build_wheel(tmp_path) subprocess.run( [venv.executable, '-m', 'pip', 'install', tmp_path / wheel], check=True) output = subprocess.run( [venv.executable, '-c', 'import spam; print(spam.add(1, 2))'], check=True, stdout=subprocess.PIPE).stdout assert int(output) == 3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_metadata.py0000644000000000000000000000310114516424013015573 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib import packaging.version import pyproject_metadata import pytest from mesonpy import Metadata def test_package_name(): name = 'package.Test' metadata = Metadata(name='package.Test', version=packaging.version.Version('0.0.1')) assert metadata.name == name assert metadata.canonical_name == 'package-test' def test_package_name_from_pyproject(): name = 'package.Test' pyproject = {'project': { 'name': 'package.Test', 'version': '0.0.1', }} metadata = Metadata.from_pyproject(pyproject, pathlib.Path()) assert metadata.name == name assert metadata.canonical_name == 'package-test' def test_package_name_invalid(): with pytest.raises(pyproject_metadata.ConfigurationError, match='Invalid project name'): Metadata(name='.test', version=packaging.version.Version('0.0.1')) def test_unsupported_dynamic(): pyproject = {'project': { 'name': 'unsupported-dynamic', 'version': '0.0.1', 'dynamic': ['dependencies'], }} with pytest.raises(pyproject_metadata.ConfigurationError, match='Unsupported dynamic fields: "dependencies"'): Metadata.from_pyproject(pyproject, pathlib.Path()) def test_missing_version(package_missing_version): pyproject = {'project': { 'name': 'missing-version', }} with pytest.raises(pyproject_metadata.ConfigurationError, match='Required "project.version" field is missing'): Metadata.from_pyproject(pyproject, pathlib.Path()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_options.py0000644000000000000000000000244614516424013015521 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT import os import subprocess import pytest import mesonpy ninja_ver_str = subprocess.run(['ninja', '--version'], check=True, stdout=subprocess.PIPE, text=True).stdout NINJA_VERSION = tuple(map(int, ninja_ver_str.split('.')[:3])) # Ninja 1.9 does not support the soruce^ syntax to specify a target. @pytest.mark.skipif(NINJA_VERSION < (1, 10), reason='Ninja version too old') @pytest.mark.parametrize( ('args', 'expected'), [ ([], True), (['-Dbuildtype=release'], True), (['-Dbuildtype=debug'], False), ], ids=['', '-Dbuildtype=release', '-Dbuildtype=debug'], ) def test_ndebug(package_purelib_and_platlib, tmp_path, args, expected): with mesonpy._project({'setup-args': args}) as project: command = subprocess.run( # Ask ninja what is the command that would be used to # compile a C source file (the trailing ^ is used to # specify the target that is the first output of the rule # containing the specified source file). ['ninja', '-C', os.fspath(project._build_dir), '-t', 'commands', '../plat.c^'], stdout=subprocess.PIPE, check=True).stdout assert (b'-DNDEBUG' in command) == expected ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_output.py0000644000000000000000000000174214516424013015364 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pytest import mesonpy @pytest.mark.parametrize( ('tty', 'env', 'colors'), [ (False, {}, False), (True, {}, True), (False, {'NO_COLOR': ''}, False), (True, {'NO_COLOR': ''}, False), (False, {'FORCE_COLOR': ''}, True), (True, {'FORCE_COLOR': ''}, True), (True, {'FORCE_COLOR': '', 'NO_COLOR': ''}, False), (True, {'TERM': ''}, True), (True, {'TERM': 'dumb'}, False), ], ) def test_use_ansi_colors(mocker, monkeypatch, tty, env, colors): mocker.patch('sys.stdout.isatty', return_value=tty) monkeypatch.delenv('NO_COLOR', raising=False) monkeypatch.delenv('FORCE_COLOR', raising=False) for key, value in env.items(): monkeypatch.setenv(key, value) # Clear caching by functools.lru_cache(). mesonpy._use_ansi_colors.cache_clear() assert mesonpy._use_ansi_colors() == colors ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_pep517.py0000644000000000000000000000672414516424013015052 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import shutil import subprocess import sys from typing import List import packaging.requirements import pytest import mesonpy @pytest.mark.parametrize('system_patchelf', ['patchelf', None], ids=['patchelf', 'nopatchelf']) @pytest.mark.parametrize('ninja', [None, '1.8.1', '1.8.3'], ids=['noninja', 'oldninja', 'newninja']) def test_get_requires_for_build_wheel(monkeypatch, package_pure, system_patchelf, ninja): # the NINJA environment variable affects the ninja executable lookup and breaks the test monkeypatch.delenv('NINJA', raising=False) def which(prog: str) -> bool: if prog == 'patchelf': return system_patchelf if prog == 'ninja': return ninja and 'ninja' if prog in ('ninja-build', 'samu'): return None # smoke check for the future if we add another usage raise AssertionError(f'Called with {prog}, tests not expecting that usage') subprocess_run = subprocess.run def run(cmd: List[str], *args: object, **kwargs: object) -> subprocess.CompletedProcess: if cmd == ['ninja', '--version']: return subprocess.CompletedProcess(cmd, 0, f'{ninja}\n', '') return subprocess_run(cmd, *args, **kwargs) monkeypatch.setattr(shutil, 'which', which) monkeypatch.setattr(subprocess, 'run', run) expected = set() if ninja is None or mesonpy._parse_version_string(ninja) < (1, 8, 2): expected.add('ninja') if system_patchelf is None and sys.platform.startswith('linux'): expected.add('patchelf') requirements = mesonpy.get_requires_for_build_wheel() # Check that the requirement strings are in the correct format. names = {packaging.requirements.Requirement(x).name for x in requirements} assert names == expected def test_invalid_config_settings(capsys, package_pure, tmp_path_session): for method in mesonpy.build_sdist, mesonpy.build_wheel: with pytest.raises(SystemExit): method(tmp_path_session, {'invalid': ()}) out, err = capsys.readouterr() assert 'Unknown option "invalid"' in out def test_invalid_config_settings_suggest(capsys, package_pure, tmp_path_session): for method in mesonpy.build_sdist, mesonpy.build_wheel: with pytest.raises(SystemExit): method(tmp_path_session, {'setup_args': ()}) out, err = capsys.readouterr() assert 'Unknown option "setup_args". Did you mean "setup-args" or "dist-args"?' in out def test_validate_config_settings_invalid(): with pytest.raises(mesonpy.ConfigError, match='Unknown option "invalid"'): mesonpy._validate_config_settings({'invalid': ()}) def test_validate_config_settings_repeated(): with pytest.raises(mesonpy.ConfigError, match='Only one value for "builddir" can be specified'): mesonpy._validate_config_settings({'builddir': ['one', 'two']}) def test_validate_config_settings_str(): config = mesonpy._validate_config_settings({'setup-args': '-Dfoo=true'}) assert config['setup-args'] == ['-Dfoo=true'] def test_validate_config_settings_list(): config = mesonpy._validate_config_settings({'setup-args': ['-Done=1', '-Dtwo=2']}) assert config['setup-args'] == ['-Done=1', '-Dtwo=2'] def test_validate_config_settings_tuple(): config = mesonpy._validate_config_settings({'setup-args': ('-Done=1', '-Dtwo=2')}) assert config['setup-args'] == ['-Done=1', '-Dtwo=2'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_project.py0000644000000000000000000001655014516424013015475 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import ast import os import shutil import sys import textwrap if sys.version_info < (3, 11): import tomli as tomllib else: import tomllib import pyproject_metadata import pytest import mesonpy from .conftest import in_git_repo_context, package_dir def test_unsupported_python_version(package_unsupported_python_version): with pytest.raises(mesonpy.MesonBuilderError, match='Package requires Python version ==1.0.0'): with mesonpy._project(): pass def test_missing_meson_version(package_missing_meson_version): with pytest.raises(pyproject_metadata.ConfigurationError, match='Section "project" missing in pyproject.toml'): with mesonpy._project(): pass def test_missing_dynamic_version(package_missing_dynamic_version): with pytest.raises(pyproject_metadata.ConfigurationError, match='Field "version" declared as dynamic but'): with mesonpy._project(): pass def test_user_args(package_user_args, tmp_path, monkeypatch): project_run = mesonpy.Project._run cmds = [] args = [] def wrapper(self, cmd): # intercept and filter out test arguments and forward the call if cmd[:2] == ['meson', 'compile']: # when using meson compile instead of ninja directly, the # arguments needs to be unmarshalled from the form used to # pass them to the --ninja-args option assert cmd[-1].startswith('--ninja-args=') cmds.append(cmd[:2]) args.append(ast.literal_eval(cmd[-1].split('=')[1])) elif cmd[:1] == ['meson']: cmds.append(cmd[:2]) args.append(cmd[2:]) else: # direct ninja invocation cmds.append([os.path.basename(cmd[0])]) args.append(cmd[1:]) return project_run(self, [x for x in cmd if not x.startswith(('config-', 'cli-', '--ninja-args'))]) monkeypatch.setattr(mesonpy.Project, '_run', wrapper) config_settings = { 'dist-args': ('cli-dist',), 'setup-args': ('cli-setup',), 'compile-args': ('cli-compile',), 'install-args': ('cli-install',), } with in_git_repo_context(): mesonpy.build_sdist(tmp_path, config_settings) mesonpy.build_wheel(tmp_path, config_settings) # check that the right commands are executed, namely that 'meson # compile' is used on Windows rather than a 'ninja' direct # invocation. assert cmds == [ # sdist: calls to 'meson setup' and 'meson dist' ['meson', 'setup'], ['meson', 'dist'], # wheel: calls to 'meson setup', 'meson compile', and 'meson install' ['meson', 'setup'], ['meson', 'compile'] if sys.platform == 'win32' else ['ninja'], ] # check that the user options are passed to the invoked commands expected = [ # sdist: calls to 'meson setup' and 'meson dist' ['config-setup', 'cli-setup'], ['config-dist', 'cli-dist'], # wheel: calls to 'meson setup', 'meson compile', and 'meson install' ['config-setup', 'cli-setup'], ['config-compile', 'cli-compile'], ['config-install', 'cli-install'], ] for expected_args, cmd_args in zip(expected, args): for arg in expected_args: assert arg in cmd_args @pytest.mark.parametrize('package', ('top-level', 'meson-args')) def test_unknown_user_args(package, tmp_path_session): with pytest.raises(mesonpy.ConfigError): mesonpy.Project(package_dir / f'unknown-user-args-{package}', tmp_path_session) def test_install_tags(package_purelib_and_platlib, tmp_path_session): project = mesonpy.Project( package_purelib_and_platlib, tmp_path_session, meson_args={ 'install': ['--tags', 'purelib'], } ) assert 'platlib' not in project._manifest def test_validate_pyproject_config_one(): pyproject_config = tomllib.loads(textwrap.dedent(''' [tool.meson-python.args] setup = ['-Dfoo=true'] ''')) conf = mesonpy._validate_pyproject_config(pyproject_config) assert conf['args'] == {'setup': ['-Dfoo=true']} def test_validate_pyproject_config_all(): pyproject_config = tomllib.loads(textwrap.dedent(''' [tool.meson-python.args] setup = ['-Dfoo=true'] dist = [] compile = ['-j4'] install = ['--tags=python'] ''')) conf = mesonpy._validate_pyproject_config(pyproject_config) assert conf['args'] == { 'setup': ['-Dfoo=true'], 'dist': [], 'compile': ['-j4'], 'install': ['--tags=python']} def test_validate_pyproject_config_unknown(): pyproject_config = tomllib.loads(textwrap.dedent(''' [tool.meson-python.args] invalid = true ''')) with pytest.raises(mesonpy.ConfigError, match='Unknown configuration entry "tool.meson-python.args.invalid"'): mesonpy._validate_pyproject_config(pyproject_config) def test_validate_pyproject_config_empty(): pyproject_config = tomllib.loads(textwrap.dedent('')) config = mesonpy._validate_pyproject_config(pyproject_config) assert config == {} @pytest.mark.skipif( sys.version_info < (3, 8), reason="unittest.mock doesn't support the required APIs for this test", ) def test_invalid_build_dir(package_pure, tmp_path, mocker): meson = mocker.spy(mesonpy.Project, '_run') # configure the project project = mesonpy.Project(package_pure, tmp_path) assert len(meson.call_args_list) == 1 assert meson.call_args_list[0].args[1][1] == 'setup' assert '--reconfigure' not in meson.call_args_list[0].args[1] project.build() meson.reset_mock() # subsequent builds with the same build directory result in a setup --reconfigure project = mesonpy.Project(package_pure, tmp_path) assert len(meson.call_args_list) == 1 assert meson.call_args_list[0].args[1][1] == 'setup' assert '--reconfigure' in meson.call_args_list[0].args[1] project.build() meson.reset_mock() # corrupting the build direcory setup is run again tmp_path.joinpath('meson-private/coredata.dat').unlink() project = mesonpy.Project(package_pure, tmp_path) assert len(meson.call_args_list) == 1 assert meson.call_args_list[0].args[1][1] == 'setup' assert '--reconfigure' not in meson.call_args_list[0].args[1] project.build() meson.reset_mock() # removing the build directory things should still work shutil.rmtree(tmp_path) project = mesonpy.Project(package_pure, tmp_path) assert len(meson.call_args_list) == 1 assert meson.call_args_list[0].args[1][1] == 'setup' assert '--reconfigure' not in meson.call_args_list[0].args[1] project.build() @pytest.mark.skipif(not os.getenv('CI') or sys.platform != 'win32', reason='Requires MSVC') def test_compiler(venv, package_detect_compiler, tmp_path): # Check that things are setup properly to use the MSVC compiler on # Windows. This effectively means running the compilation step # with 'meson compile' instead of 'ninja' on Windows. Run this # test only on CI where we know that MSVC is available. wheel = mesonpy.build_wheel(tmp_path, {'setup-args': ['--vsenv']}) venv.pip('install', os.fspath(tmp_path / wheel)) compiler = venv.python('-c', 'import detect_compiler; print(detect_compiler.compiler())').strip() assert compiler == 'msvc' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_sdist.py0000644000000000000000000001371314516424013015153 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import os import stat import sys import tarfile import textwrap import pytest import mesonpy from .conftest import in_git_repo_context def test_no_pep621(sdist_library): with tarfile.open(sdist_library, 'r:gz') as sdist: sdist_pkg_info = sdist.extractfile('library-1.0.0/PKG-INFO').read().decode() assert sdist_pkg_info == textwrap.dedent('''\ Metadata-Version: 2.1 Name: library Version: 1.0.0 ''') def test_pep621(sdist_full_metadata): with tarfile.open(sdist_full_metadata, 'r:gz') as sdist: sdist_pkg_info = sdist.extractfile('full_metadata-1.2.3/PKG-INFO').read().decode() assert sdist_pkg_info == textwrap.dedent('''\ Metadata-Version: 2.1 Name: full-metadata Version: 1.2.3 Summary: Some package with all of the PEP 621 metadata Keywords: full metadata Home-page: https://example.com Author: Jane Doe Author-Email: Unknown Maintainer-Email: Jane Doe License: some license Classifier: Development Status :: 4 - Beta Classifier: Programming Language :: Python Project-URL: Homepage, https://example.com Project-URL: Documentation, https://readthedocs.org Project-URL: Repository, https://github.com/mesonbuild/meson-python Project-URL: Changelog, https://github.com/mesonbuild/meson-python/blob/master/CHANGELOG.rst Requires-Python: >=3.7 Requires-Dist: a Requires-Dist: b>1 Requires-Dist: c>2; os_name != "nt" Requires-Dist: d<3; extra == "test" Requires-Dist: e[all]; extra == "test" Provides-Extra: test Description-Content-Type: text/markdown # full-metadata An example package with all of the PEP 621 metadata! ''') def test_dynamic_version(sdist_dynamic_version): with tarfile.open(sdist_dynamic_version, 'r:gz') as sdist: sdist_pkg_info = sdist.extractfile('dynamic_version-1.0.0/PKG-INFO').read().decode() assert sdist_pkg_info == textwrap.dedent('''\ Metadata-Version: 2.1 Name: dynamic-version Version: 1.0.0 ''') def test_contents(sdist_library): with tarfile.open(sdist_library, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} mtimes = {member.mtime for member in sdist.getmembers()} assert names == { 'library-1.0.0/example.c', 'library-1.0.0/examplelib.c', 'library-1.0.0/examplelib.h', 'library-1.0.0/meson.build', 'library-1.0.0/pyproject.toml', 'library-1.0.0/PKG-INFO', } # All the archive members have a valid mtime. assert 0 not in mtimes def test_contents_subdirs(sdist_subdirs): with tarfile.open(sdist_subdirs, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} mtimes = {member.mtime for member in sdist.getmembers()} assert names == { 'subdirs-1.0.0/PKG-INFO', 'subdirs-1.0.0/meson.build', 'subdirs-1.0.0/pyproject.toml', 'subdirs-1.0.0/subdirs/__init__.py', 'subdirs-1.0.0/subdirs/a/__init__.py', 'subdirs-1.0.0/subdirs/a/b/c.py', 'subdirs-1.0.0/subdirs/b/c.py', } # All the archive members have a valid mtime. assert 0 not in mtimes def test_contents_unstaged(package_pure, tmp_path): new_data = textwrap.dedent(''' def bar(): return 'foo' ''').strip() with open('pure.py', 'r') as f: old_data = f.read() try: with in_git_repo_context(): with open('pure.py', 'w') as f, open('crap', 'x'): f.write(new_data) sdist_path = mesonpy.build_sdist(os.fspath(tmp_path)) finally: with open('pure.py', 'w') as f: f.write(old_data) os.unlink('crap') with tarfile.open(tmp_path / sdist_path, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} mtimes = {member.mtime for member in sdist.getmembers()} read_data = sdist.extractfile('pure-1.0.0/pure.py').read().replace(b'\r\n', b'\n') assert names == { 'pure-1.0.0/PKG-INFO', 'pure-1.0.0/meson.build', 'pure-1.0.0/pure.py', 'pure-1.0.0/pyproject.toml', } assert read_data == new_data.encode() # All the archive members have a valid mtime. assert 0 not in mtimes @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='Platform does not support executable bit') def test_executable_bit(sdist_executable_bit): expected = { 'executable_bit-1.0.0/PKG-INFO': False, 'executable_bit-1.0.0/example-script.py': True, 'executable_bit-1.0.0/example.c': False, 'executable_bit-1.0.0/executable_module.py': True, 'executable_bit-1.0.0/meson.build': False, 'executable_bit-1.0.0/pyproject.toml': False, } with tarfile.open(sdist_executable_bit, 'r:gz') as sdist: for member in sdist.getmembers(): assert bool(member.mode & stat.S_IXUSR) == expected[member.name] def test_generated_files(sdist_generated_files): with tarfile.open(sdist_generated_files, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} mtimes = {member.mtime for member in sdist.getmembers()} assert names == { 'executable_bit-1.0.0/PKG-INFO', 'executable_bit-1.0.0/example-script.py', 'executable_bit-1.0.0/example.c', 'executable_bit-1.0.0/executable_module.py', 'executable_bit-1.0.0/meson.build', 'executable_bit-1.0.0/pyproject.toml', 'executable_bit-1.0.0/_version_meson.py', 'executable_bit-1.0.0/generate_version.py', } # All the archive members have a valid mtime. assert 0 not in mtimes ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_tags.py0000644000000000000000000000673214516424013014766 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import importlib.machinery import os import pathlib import sys import sysconfig from collections import defaultdict import packaging.tags import pytest import mesonpy import mesonpy._tags from .conftest import adjust_packaging_platform_tag # Test against the wheel tag generated by packaging module. tag = next(packaging.tags.sys_tags()) ABI = tag.abi INTERPRETER = tag.interpreter PLATFORM = adjust_packaging_platform_tag(tag.platform) def get_abi3_suffix(): for suffix in importlib.machinery.EXTENSION_SUFFIXES: if '.abi3' in suffix: # Unix return suffix elif suffix == '.pyd': # Windows return suffix SUFFIX = sysconfig.get_config_var('EXT_SUFFIX') ABI3SUFFIX = get_abi3_suffix() def test_wheel_tag(): assert str(mesonpy._tags.Tag()) == f'{INTERPRETER}-{ABI}-{PLATFORM}' assert str(mesonpy._tags.Tag(abi='abi3')) == f'{INTERPRETER}-abi3-{PLATFORM}' @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') def test_macos_platform_tag(monkeypatch): for minor in range(9, 16): monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'10.{minor}') assert next(packaging.tags.mac_platforms((10, minor))) == mesonpy._tags.get_platform_tag() for major in range(11, 20): for minor in range(3): monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'{major}.{minor}') assert next(packaging.tags.mac_platforms((major, minor))) == mesonpy._tags.get_platform_tag() @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') def test_python_host_platform(monkeypatch): monkeypatch.setenv('_PYTHON_HOST_PLATFORM', 'macosx-12.0-arm64') assert mesonpy._tags.get_platform_tag().endswith('arm64') monkeypatch.setenv('_PYTHON_HOST_PLATFORM', 'macosx-11.1-x86_64') assert mesonpy._tags.get_platform_tag().endswith('x86_64') def wheel_builder_test_factory(content, pure=True, limited_api=False): manifest = defaultdict(list) manifest.update({key: [(pathlib.Path(x), os.path.join('build', x)) for x in value] for key, value in content.items()}) return mesonpy._WheelBuilder(None, manifest, limited_api) def test_tag_empty_wheel(): builder = wheel_builder_test_factory({}) assert str(builder.tag) == 'py3-none-any' def test_tag_purelib_wheel(): builder = wheel_builder_test_factory({ 'purelib': ['pure.py'], }) assert str(builder.tag) == 'py3-none-any' def test_tag_platlib_wheel(): builder = wheel_builder_test_factory({ 'platlib': [f'extension{SUFFIX}'], }) assert str(builder.tag) == f'{INTERPRETER}-{ABI}-{PLATFORM}' def test_tag_stable_abi(): builder = wheel_builder_test_factory({ 'platlib': [f'extension{ABI3SUFFIX}'], }, limited_api=True) assert str(builder.tag) == f'{INTERPRETER}-abi3-{PLATFORM}' @pytest.mark.xfail(sys.version_info < (3, 8) and sys.platform == 'win32', reason='Extension modules suffix without ABI tags') @pytest.mark.xfail('__pypy__' in sys.builtin_module_names, reason='PyPy does not use special modules suffix for stable ABI') def test_tag_mixed_abi(): builder = wheel_builder_test_factory({ 'platlib': [f'extension{ABI3SUFFIX}', f'another{SUFFIX}'], }, pure=False, limited_api=True) with pytest.raises(mesonpy.BuildError, match='The package declares compatibility with Python limited API but '): assert str(builder.tag) == f'{INTERPRETER}-abi3-{PLATFORM}' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_wheel.py0000644000000000000000000003075314516424013015134 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import os import re import shutil import stat import subprocess import sys import sysconfig import textwrap import packaging.tags import pytest import wheel.wheelfile import mesonpy from .conftest import adjust_packaging_platform_tag _meson_ver_str = subprocess.run(['meson', '--version'], check=True, stdout=subprocess.PIPE, text=True).stdout MESON_VERSION = tuple(map(int, _meson_ver_str.split('.')[:3])) EXT_SUFFIX = sysconfig.get_config_var('EXT_SUFFIX') if sys.version_info <= (3, 8, 7): if MESON_VERSION >= (0, 99): # Fixed in Meson 1.0, see https://github.com/mesonbuild/meson/pull/10961. from distutils.sysconfig import get_config_var EXT_SUFFIX = get_config_var('EXT_SUFFIX') if sys.platform in {'win32', 'cygwin'}: EXT_IMP_SUFFIX = re.sub(r'.(pyd|dll)$', '.lib' if shutil.which('cl.exe') else '.dll.a', EXT_SUFFIX) LIB_SUFFIX = { 'cygwin': '.dll', 'darwin': '.dylib', 'win32': '.dll', }.get(sys.platform, '.so') # Test against the wheel tag generated by packaging module. tag = next(packaging.tags.sys_tags()) ABI = tag.abi INTERPRETER = tag.interpreter PLATFORM = adjust_packaging_platform_tag(tag.platform) def wheel_contents(artifact): # Sometimes directories have entries, sometimes not, so we filter them out. return { entry for entry in artifact.namelist() if not entry.endswith('/') } def test_scipy_like(wheel_scipy_like): # This test is meant to exercise features commonly needed by a regular # Python package for scientific computing or data science: # - C and Cython extensions, # - including generated code, # - using `install_subdir`, # - packaging data files with extensions not known to Meson artifact = wheel.wheelfile.WheelFile(wheel_scipy_like) expecting = { 'mypkg-2.3.4.dist-info/METADATA', 'mypkg-2.3.4.dist-info/RECORD', 'mypkg-2.3.4.dist-info/WHEEL', 'mypkg/__init__.py', 'mypkg/__config__.py', f'mypkg/extmod{EXT_SUFFIX}', f'mypkg/cy_extmod{EXT_SUFFIX}', 'mypkg/submod/__init__.py', 'mypkg/submod/unknown_filetype.npq', } if sys.platform in {'win32', 'cygwin'}: # Currently Meson is installing .dll.a (import libraries) next # to .pyd extension modules. Those are very small, so it's not # a major issue - just sloppy. Ensure we don't fail on those. expecting.update({ f'mypkg/extmod{EXT_IMP_SUFFIX}', f'mypkg/cy_extmod{EXT_IMP_SUFFIX}', }) assert wheel_contents(artifact) == expecting name = artifact.parsed_filename assert name.group('pyver') == INTERPRETER assert name.group('abi') == ABI assert name.group('plat') == PLATFORM def test_purelib_and_platlib(wheel_purelib_and_platlib): artifact = wheel.wheelfile.WheelFile(wheel_purelib_and_platlib) expecting = { f'plat{EXT_SUFFIX}', 'purelib_and_platlib-1.0.0.data/purelib/pure.py', 'purelib_and_platlib-1.0.0.dist-info/METADATA', 'purelib_and_platlib-1.0.0.dist-info/RECORD', 'purelib_and_platlib-1.0.0.dist-info/WHEEL', } if sys.platform in {'win32', 'cygwin'}: # Currently Meson is installing .dll.a (import libraries) next # to .pyd extension modules. Those are very small, so it's not # a major issue - just sloppy. Ensure we don't fail on those. expecting.update({ f'plat{EXT_IMP_SUFFIX}' }) assert wheel_contents(artifact) == expecting def test_pure(wheel_pure): artifact = wheel.wheelfile.WheelFile(wheel_pure) assert wheel_contents(artifact) == { 'pure-1.0.0.dist-info/METADATA', 'pure-1.0.0.dist-info/RECORD', 'pure-1.0.0.dist-info/WHEEL', 'pure.py', } def test_configure_data(wheel_configure_data): artifact = wheel.wheelfile.WheelFile(wheel_configure_data) assert wheel_contents(artifact) == { 'configure_data.py', 'configure_data-1.0.0.dist-info/METADATA', 'configure_data-1.0.0.dist-info/RECORD', 'configure_data-1.0.0.dist-info/WHEEL', } def test_contents_license_file(wheel_license_file): artifact = wheel.wheelfile.WheelFile(wheel_license_file) assert artifact.read('license_file-1.0.0.dist-info/LICENSE.custom').rstrip() == b'Hello!' @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_contents(package_library, wheel_library): artifact = wheel.wheelfile.WheelFile(wheel_library) assert wheel_contents(artifact) == { f'.library.mesonpy.libs/libexample{LIB_SUFFIX}', 'library-1.0.0.data/headers/examplelib.h', 'library-1.0.0.data/scripts/example', 'library-1.0.0.dist-info/METADATA', 'library-1.0.0.dist-info/RECORD', 'library-1.0.0.dist-info/WHEEL', } @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_local_lib(venv, wheel_link_against_local_lib): venv.pip('install', wheel_link_against_local_lib) output = venv.python('-c', 'import example; print(example.example_sum(1, 2))') assert int(output) == 3 @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_rpath(wheel_link_against_local_lib, tmp_path): artifact = wheel.wheelfile.WheelFile(wheel_link_against_local_lib) artifact.extractall(tmp_path) origin = {'linux': '$ORIGIN', 'darwin': '@loader_path'}[sys.platform] expected = {f'{origin}/.link_against_local_lib.mesonpy.libs', 'custom-rpath',} rpath = set(mesonpy._rpath._get_rpath(tmp_path / f'example{EXT_SUFFIX}')) # Verify that rpath is a superset of the expected one: linking to # the Python runtime may require additional rpath entries. assert rpath >= expected @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_uneeded_rpath(wheel_purelib_and_platlib, tmp_path): artifact = wheel.wheelfile.WheelFile(wheel_purelib_and_platlib) artifact.extractall(tmp_path) origin = {'linux': '$ORIGIN', 'darwin': '@loader_path'}[sys.platform] rpath = mesonpy._rpath._get_rpath(tmp_path / f'plat{EXT_SUFFIX}') for path in rpath: assert origin not in path @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_executable_bit(wheel_executable_bit): artifact = wheel.wheelfile.WheelFile(wheel_executable_bit) executable_files = { 'executable_bit-1.0.0.data/purelib/executable_module.py', 'executable_bit-1.0.0.data/scripts/example', 'executable_bit-1.0.0.data/scripts/example-script', } for info in artifact.infolist(): mode = (info.external_attr >> 16) & 0o777 assert bool(mode & stat.S_IXUSR) == (info.filename in executable_files) def test_detect_wheel_tag_module(wheel_purelib_and_platlib): name = wheel.wheelfile.WheelFile(wheel_purelib_and_platlib).parsed_filename assert name.group('pyver') == INTERPRETER assert name.group('abi') == ABI assert name.group('plat') == PLATFORM def test_detect_wheel_tag_script(wheel_executable): name = wheel.wheelfile.WheelFile(wheel_executable).parsed_filename assert name.group('pyver') == 'py3' assert name.group('abi') == 'none' assert name.group('plat') == PLATFORM def test_entrypoints(wheel_full_metadata): artifact = wheel.wheelfile.WheelFile(wheel_full_metadata) with artifact.open('full_metadata-1.2.3.dist-info/entry_points.txt') as f: assert f.read().decode().strip() == textwrap.dedent(''' [something.custom] example = example:custom [console_scripts] example-cli = example:cli [gui_scripts] example-gui = example:gui ''').strip() def test_top_level_modules(package_module_types): with mesonpy._project() as project: builder = mesonpy._EditableWheelBuilder(project._metadata, project._manifest, project._limited_api) assert set(builder._top_level_modules) == { 'file', 'package', 'namespace', 'native', } def test_purelib_platlib_split(package_purelib_platlib_split, tmp_path): with pytest.raises(mesonpy.BuildError, match='The purelib-platlib-split package is split'): with mesonpy._project() as project: project.wheel(tmp_path) @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') @pytest.mark.parametrize(('arch'), ['x86_64', 'arm64']) def test_archflags_envvar(package_purelib_and_platlib, monkeypatch, tmp_path, arch): try: monkeypatch.setenv('ARCHFLAGS', f'-arch {arch}') filename = mesonpy.build_wheel(tmp_path) name = wheel.wheelfile.WheelFile(tmp_path / filename).parsed_filename assert name.group('plat').endswith(arch) finally: # revert environment variable setting done by the in-process build if '_PYTHON_HOST_PLATFORM' in os.environ: del os.environ['_PYTHON_HOST_PLATFORM'] def test_subprojects(package_subproject, tmp_path): filename = mesonpy.build_wheel(tmp_path) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) assert wheel_contents(artifact) == { 'subproject-1.0.0.dist-info/METADATA', 'subproject-1.0.0.dist-info/RECORD', 'subproject-1.0.0.dist-info/WHEEL', 'subproject.py', 'dep.py', } # Requires Meson 1.2.0, see https://github.com/mesonbuild/meson/pull/11909. @pytest.mark.skipif(MESON_VERSION < (1, 1, 99), reason='Meson version too old') @pytest.mark.parametrize(('arg'), ['--skip-subprojects', '--skip-subprojects=dep']) def test_skip_subprojects(package_subproject, tmp_path, arg): filename = mesonpy.build_wheel(tmp_path, {'install-args': [arg]}) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) assert wheel_contents(artifact) == { 'subproject-1.0.0.dist-info/METADATA', 'subproject-1.0.0.dist-info/RECORD', 'subproject-1.0.0.dist-info/WHEEL', 'subproject.py', } # Requires Meson 1.3.0, see https://github.com/mesonbuild/meson/pull/11745. @pytest.mark.skipif(MESON_VERSION < (1, 2, 99), reason='Meson version too old') def test_limited_api(wheel_limited_api): artifact = wheel.wheelfile.WheelFile(wheel_limited_api) name = artifact.parsed_filename assert name.group('pyver') == INTERPRETER assert name.group('abi') == 'abi3' assert name.group('plat') == PLATFORM # Requires Meson 1.3.0, see https://github.com/mesonbuild/meson/pull/11745. @pytest.mark.skipif(MESON_VERSION < (1, 2, 99), reason='Meson version too old') @pytest.mark.xfail('__pypy__' in sys.builtin_module_names, reason='PyPy does not use special modules suffix for stable ABI') def test_limited_api_bad(package_limited_api, tmp_path): with pytest.raises(mesonpy.BuildError, match='The package declares compatibility with Python limited API but '): with mesonpy._project({'setup-args': ['-Dextra=true']}) as project: project.wheel(tmp_path) # Requires Meson 1.3.0, see https://github.com/mesonbuild/meson/pull/11745. @pytest.mark.skipif(MESON_VERSION < (1, 2, 99), reason='Meson version too old') def test_limited_api_disabled(package_limited_api, tmp_path): filename = mesonpy.build_wheel(tmp_path, {'setup-args': ['-Dpython.allow_limited_api=false']}) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) name = artifact.parsed_filename assert name.group('pyver') == INTERPRETER assert name.group('abi') == ABI assert name.group('plat') == PLATFORM def test_install_subdir(wheel_install_subdir): artifact = wheel.wheelfile.WheelFile(wheel_install_subdir) # Handling of the exclude_files and exclude_directories requires # Meson 1.1.0, see https://github.com/mesonbuild/meson/pull/11432. # Run the test anyway to ensure that meson-python can produce a # wheel also for older versions of Meson. if MESON_VERSION >= (1, 1, 99): assert wheel_contents(artifact) == { 'install_subdir-1.0.0.dist-info/METADATA', 'install_subdir-1.0.0.dist-info/RECORD', 'install_subdir-1.0.0.dist-info/WHEEL', 'subdir/__init__.py', 'subdir/test.py', 'test/module.py', 'nested/deep/deep.py', 'nested/nested.py', } def test_vendored_meson(wheel_vendored_meson): # This test will error if the vendored meson.py wrapper script in # the test package isn't used. pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1698310155.0 meson_python-0.15.0/tests/test_wheelfile.py0000644000000000000000000000350314516424013015765 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT import contextlib import time import zipfile import wheel.wheelfile import mesonpy._wheelfile def test_basic(tmp_path): path = tmp_path / 'test-1.0-py3-any-none.whl' bar = tmp_path / 'bar' bar.write_bytes(b'bar') with mesonpy._wheelfile.WheelFile(path, 'w') as w: assert w.name == 'test' assert w.version == '1.0' w.writestr('foo', b'test') w.write(bar, 'bar') with contextlib.closing(wheel.wheelfile.WheelFile(path, 'r')) as w: assert set(w.namelist()) == {'foo', 'bar', 'test-1.0.dist-info/RECORD'} with w.open('foo') as foo: assert foo.read() == b'test' with w.open('bar') as bar: assert bar.read() == b'bar' def test_source_date_epoch(tmp_path, monkeypatch): path = tmp_path / 'test-1.0-py3-any-none.whl' epoch = 1668871912 # The ZIP file format timestamps have 2 seconds resolution. assert epoch % 2 == 0 monkeypatch.setenv('SOURCE_DATE_EPOCH', str(epoch)) bar = tmp_path / 'bar' bar.write_bytes(b'bar') with mesonpy._wheelfile.WheelFile(path, 'w') as w: w.writestr('foo', b'test') w.write(bar, 'bar') with wheel.wheelfile.WheelFile(path, 'r') as w: for entry in w.infolist(): assert entry.date_time == time.gmtime(epoch)[:6] def test_compression(tmp_path): # create a wheel and test that everything is compressed path = tmp_path / 'test-1.0-py3-any-none.whl' bar = tmp_path / 'bar' bar.write_bytes(b'bar') with mesonpy._wheelfile.WheelFile(path, 'w') as w: w.writestr('foo', b'test') w.write(bar, 'bar') with zipfile.ZipFile(path, 'r') as w: for entry in w.infolist(): assert entry.compress_type == zipfile.ZIP_DEFLATED ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1698311297.927498 meson_python-0.15.0/PKG-INFO0000644000000000000000000000774714516426202012363 0ustar00Metadata-Version: 2.1 Name: meson-python Version: 0.15.0 Summary: Meson Python build backend (PEP 517) Keywords: meson build backend pep517 package Home-page: https://github.com/mesonbuild/meson-python Maintainer: Thomas Li Maintainer-Email: Ralf Gommers , Daniele Nicolodi , Henry Schreiner License: Copyright © 2022 the meson-python contributors Copyright © 2021 Quansight Labs and Filipe Laíns Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Classifier: Development Status :: 5 - Production/Stable Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Build Tools Project-URL: Homepage, https://github.com/mesonbuild/meson-python Project-URL: Repository, https://github.com/mesonbuild/meson-python Project-URL: Documentation, https://meson-python.readthedocs.io/ Project-URL: Changelog, https://meson-python.readthedocs.io/en/latest/changelog.html Requires-Python: >=3.7 Requires-Dist: colorama; os_name == "nt" Requires-Dist: meson>=0.63.3; python_version < "3.12" Requires-Dist: meson>=1.2.3; python_version >= "3.12" Requires-Dist: pyproject-metadata>=0.7.1 Requires-Dist: tomli>=1.0.0; python_version < "3.11" Requires-Dist: build; extra == "test" Requires-Dist: pytest>=6.0; extra == "test" Requires-Dist: pytest-cov[toml]; extra == "test" Requires-Dist: pytest-mock; extra == "test" Requires-Dist: cython>=3.0.3; extra == "test" Requires-Dist: wheel; extra == "test" Requires-Dist: typing-extensions>=3.7.4; python_version < "3.11" and extra == "test" Requires-Dist: furo>=2021.08.31; extra == "docs" Requires-Dist: sphinx~=4.0; extra == "docs" Requires-Dist: sphinx-copybutton>=0.5.0; extra == "docs" Requires-Dist: sphinx-design>=0.1.0; extra == "docs" Requires-Dist: sphinxext-opengraph>=0.7.0; extra == "docs" Provides-Extra: test Provides-Extra: docs Description-Content-Type: text/x-rst .. SPDX-FileCopyrightText: 2021 The meson-python developers .. SPDX-License-Identifier: MIT meson-python ============ ``meson-python`` is a Python build backend built on top of the Meson__ build system. It enables to use Meson for the configuration and build steps of Python packages. Meson is an open source build system meant to be both extremely fast, and, even more importantly, as user friendly as possible. ``meson-python`` is best suited for building Python packages containing extension modules implemented in languages such as C, C++, Cython, Fortran, Pythran, or Rust. Consult the documentation__ for more details. Questions regarding the use of ``meson-python`` can be directed to the discussions__ space on GitHub. Bug reports and feature requests can be filed as GitHub issues__. __ https://mesonbuild.com/ __ https://meson-python.readthedocs.io/en/latest/ __ https://github.com/mesonbuild/meson-python/discussions/ __ https://github.com/mesonbuild/meson-python/issues/