├── .cirrus.yml ├── .codespellrc ├── .config └── nextest.toml ├── .devcontainer ├── devcontainer.json └── post_create.sh ├── .dockerignore ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.md ├── bors.toml ├── dependabot.yml └── workflows │ ├── clear-cache.yml │ ├── docker.yml │ ├── downstream.yml │ ├── release.yml │ ├── test.yml │ └── update-auditwheel.yml ├── .gitignore ├── .pre-commit-config.yaml ├── Cargo.lock ├── Cargo.toml ├── Changelog.md ├── Code-of-Conduct.md ├── Dockerfile ├── MANIFEST.in ├── README.md ├── clippy.toml ├── deny.toml ├── guide ├── .gitignore ├── book.toml ├── src │ ├── SUMMARY.md │ ├── assets │ │ └── sponsors │ │ │ ├── astral.png │ │ │ ├── bytewax.png │ │ │ ├── frontend-masters.png │ │ │ ├── prefect.png │ │ │ ├── pydantic.png │ │ │ ├── quansightlabs.jpeg │ │ │ ├── rerun.png │ │ │ ├── sentry.png │ │ │ └── tsy-capital.png │ ├── bindings.md │ ├── changelog.md │ ├── config.md │ ├── contributing.md │ ├── distribution.md │ ├── environment-variables.md │ ├── import_hook.md │ ├── index.md │ ├── installation.md │ ├── local_development.md │ ├── metadata.md │ ├── migration.md │ ├── platform_support.md │ ├── project_layout.md │ ├── sphinx.md │ └── tutorial.md └── tweak.css ├── license-apache ├── license-mit ├── maturin.schema.json ├── maturin ├── __init__.py ├── __main__.py └── bootstrap.py ├── netlify.toml ├── noxfile.py ├── pyproject.toml ├── setup.py ├── src ├── auditwheel │ ├── audit.rs │ ├── manylinux-policy.json │ ├── mod.rs │ ├── musllinux-policy.json │ ├── musllinux.rs │ ├── patchelf.rs │ ├── platform_tag.rs │ ├── policy.rs │ └── repair.rs ├── bridge.rs ├── build_context.rs ├── build_options.rs ├── cargo_toml.rs ├── ci.rs ├── compile.rs ├── cross_compile.rs ├── develop.rs ├── generate_json_schema.rs ├── lib.rs ├── main.rs ├── metadata.rs ├── module_writer.rs ├── new_project.rs ├── project_layout.rs ├── pyproject_toml.rs ├── python_interpreter │ ├── config.rs │ ├── get_interpreter_metadata.py │ └── mod.rs ├── source_distribution.rs ├── target.rs ├── templates │ ├── .gitignore.j2 │ ├── Cargo.toml.j2 │ ├── __init__.py.j2 │ ├── build.rs.j2 │ ├── example.udl.j2 │ ├── lib.rs.j2 │ ├── main.rs.j2 │ ├── pyproject.toml.j2 │ └── test_all.py.j2 └── upload.rs ├── sysconfig ├── Readme.md ├── cpython-aix-3.9.txt ├── cpython-android-3.8-aarch64.txt ├── cpython-dragonfly-3.8.txt ├── cpython-freebsd-11.2.txt ├── cpython-freebsd-13.0-aarch64.txt ├── cpython-freebsd-13.0-powerpc64.txt ├── cpython-freebsd-13.0-powerpc64le.txt ├── cpython-freebsd-13.1-armv7.txt ├── cpython-freebsd-14.0-riscv64.txt ├── cpython-gnu-3.12.txt ├── cpython-haiku-3.9.txt ├── cpython-linux-3.7.txt ├── cpython-linux-3.8-aarch64.txt ├── cpython-linux-3.8.txt ├── cpython-linux-3.9.txt ├── cpython-linux-armv5te-3.11.txt ├── cpython-linux-mips64-3.11.txt ├── cpython-linux-mips64el-3.10.txt ├── cpython-macos-3.9-arm64.txt ├── cpython-netbsd-3.9.txt ├── cpython-omnios-3.9.txt ├── cpython-openbsd-3.8-aarch64.txt ├── cpython-openbsd-3.8.txt ├── cpython-wasi-3.12.txt ├── cpython-win-3.7.txt ├── cpython-win-3.9-aarch64.txt ├── cpython-win-mingw64-3.9.txt ├── graalpy-macos-3.8-arm64.txt ├── nogil-linux-3.9.txt ├── pypy-linux-3.7-7.3.txt ├── pypy-linux-ppc64le-3.7-7.3.txt ├── pypy-linux-ppc64le-3.8-7.3.txt ├── pypy-linux-ppc64le-3.9-7.3.txt ├── pypy-linux-s390x-3.7-7.3.txt ├── pypy-linux-s390x-3.8-7.3.txt ├── pypy-linux-s390x-3.9-7.3.txt ├── pypy-macos-3.7-7.3.txt ├── pypy-windows-3.7-7.3.txt └── pyston-3.8.txt ├── test-crates ├── cargo-mock │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── cargo-update.sh ├── cffi-mixed │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Readme.md │ ├── cffi_mixed │ │ ├── __init__.py │ │ └── line.py │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── requirements_test.txt │ ├── src │ │ └── lib.rs │ ├── test_cffi_mixed.py │ └── tox.ini ├── cffi-pure │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Readme.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── requirements_test.txt │ ├── src │ │ └── lib.rs │ ├── test_cffi_pure.py │ └── tox.ini ├── hello-world │ ├── Cargo.lock │ ├── Cargo.toml │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ └── src │ │ ├── bin │ │ └── foo.rs │ │ └── main.rs ├── lib_with_disallowed_lib │ ├── Cargo.lock │ ├── Cargo.toml │ ├── pyproject.toml │ └── src │ │ └── lib.rs ├── lib_with_path_dep │ ├── Cargo.toml │ ├── pyproject.toml │ ├── src │ │ └── lib.rs │ └── test.sh ├── license-test │ ├── AUTHORS.txt │ ├── Cargo.lock │ ├── Cargo.toml │ ├── LICENCE.txt │ ├── LICENSE │ ├── NOTICE.md │ ├── _vendor │ │ ├── AUTHORS.txt │ │ ├── COPYING.md │ │ ├── LICENCE │ │ ├── LICENSE-APACHE.txt │ │ ├── NOTICE │ │ └── nested │ │ │ ├── LICENSE-BSD │ │ │ └── NOTICE.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ └── src │ │ └── main.rs ├── pyo3-abi3-without-version │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── pyo3-bin │ ├── Cargo.lock │ ├── Cargo.toml │ ├── check_installed │ │ └── check_installed.py │ └── src │ │ └── main.rs ├── pyo3-feature │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Readme.md │ └── src │ │ └── lib.rs ├── pyo3-ffi-pure │ ├── Cargo.lock │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── src │ │ └── lib.rs │ └── test_pyo3_ffi_pure.py ├── pyo3-mixed-implicit │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── python │ │ └── pyo3_mixed_implicit │ │ │ └── some_rust │ │ │ ├── __init__.py │ │ │ └── double.py │ ├── src │ │ └── lib.rs │ ├── tests │ │ └── test_pyo3_mixed_implicit.py │ └── tox.ini ├── pyo3-mixed-include-exclude │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyo3_mixed_include_exclude │ │ ├── .gitignore │ │ ├── __init__.py │ │ ├── exclude_this_file │ │ ├── include_this_file │ │ └── python_module │ │ │ ├── __init__.py │ │ │ └── double.py │ ├── pyproject.toml │ ├── src │ │ └── lib.rs │ ├── tests │ │ └── test_pyo3_mixed_include_exclude.py │ └── tox.ini ├── pyo3-mixed-py-subdir │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── python │ │ └── pyo3_mixed_py_subdir │ │ │ ├── __init__.py │ │ │ └── python_module │ │ │ ├── __init__.py │ │ │ └── double.py │ ├── src │ │ └── lib.rs │ ├── test_pyo3_mixed.py │ └── tox.ini ├── pyo3-mixed-src │ ├── .gitignore │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── rust │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── src │ │ ├── pyo3_mixed_src │ │ │ ├── __init__.py │ │ │ └── python_module │ │ │ │ ├── __init__.py │ │ │ │ └── double.py │ │ └── tests │ │ │ └── test_pyo3_mixed.py │ └── tox.ini ├── pyo3-mixed-submodule │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyo3_mixed_submodule │ │ ├── __init__.py │ │ ├── python_module │ │ │ ├── __init__.py │ │ │ └── double.py │ │ └── rust_module │ │ │ └── __init__.py │ ├── pyproject.toml │ ├── src │ │ └── lib.rs │ ├── tests │ │ └── test_pyo3_mixed_submodule.py │ └── tox.ini ├── pyo3-mixed-with-path-dep │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyo3_mixed_with_path_dep │ │ └── __init__.py │ ├── pyproject.toml │ ├── src │ │ └── lib.rs │ ├── tests │ │ └── test_pyo3_mixed_with_path_dep.py │ └── tox.ini ├── pyo3-mixed-workspace │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── rust │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── pyo3-mixed-workspace │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── python │ │ │ └── pyo3-mixed-workspace-py │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── src │ │ ├── pyo3_mixed_workspace │ │ │ ├── __init__.py │ │ │ └── python_module │ │ │ │ ├── __init__.py │ │ │ │ └── double.py │ │ └── tests │ │ │ └── test_pyo3_mixed.py │ └── tox.ini ├── pyo3-mixed │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── pyo3-config.txt │ ├── pyo3_mixed │ │ ├── __init__.py │ │ ├── assets │ │ │ └── asset.txt │ │ └── python_module │ │ │ ├── __init__.py │ │ │ └── double.py │ ├── pyproject.toml │ ├── src │ │ └── lib.rs │ ├── tests │ │ └── test_pyo3_mixed.py │ └── tox.ini ├── pyo3-no-extension-module │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── pyo3-pure │ ├── Cargo.lock │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── local-test │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── pyo3_pure.pyi │ ├── pyproject.toml │ ├── src │ │ └── lib.rs │ ├── tests │ │ └── test_pyo3_pure.py │ └── tox.ini ├── readme-duplication │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── readme-py │ │ ├── Cargo.toml │ │ ├── README.md │ │ ├── pyproject.toml │ │ └── src │ │ │ └── lib.rs │ └── readme-rs │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── sdist_with_path_dep │ ├── Cargo.lock │ ├── Cargo.toml │ ├── pyproject.toml │ └── src │ │ └── lib.rs ├── sdist_with_target_path_dep │ ├── Cargo.lock │ ├── Cargo.toml │ ├── pyproject.toml │ └── src │ │ └── lib.rs ├── some_path_dep │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── transitive_path_dep │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── uniffi-mixed │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── build.rs │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── src │ │ ├── lib.rs │ │ └── math.udl │ ├── test_uniffi_mixed.py │ └── uniffi_mixed │ │ └── __init__.py ├── uniffi-multiple-binding-files │ ├── Cargo.lock │ ├── Cargo.toml │ ├── check_installed │ │ └── check_installed.py │ ├── mylib │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── src │ │ └── lib.rs │ └── uniffi.toml ├── uniffi-pure-proc-macro │ ├── Cargo.lock │ ├── Cargo.toml │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── src │ │ └── lib.rs │ ├── test_uniffi_pure.py │ ├── uniffi-bindgen.rs │ └── uniffi.toml ├── uniffi-pure │ ├── Cargo.lock │ ├── Cargo.toml │ ├── build.rs │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── src │ │ ├── lib.rs │ │ └── math.udl │ ├── test_uniffi_pure.py │ └── uniffi.toml ├── update_readme.py ├── with-data │ ├── Cargo.lock │ ├── Cargo.toml │ ├── check_installed │ │ └── check_installed.py │ ├── pyproject.toml │ ├── src │ │ └── lib.rs │ └── with_data.data │ │ ├── data │ │ └── data_subdir │ │ │ └── hello.txt │ │ └── headers │ │ └── empty.h ├── workspace-inheritance │ ├── Cargo.lock │ ├── Cargo.toml │ ├── generic_lib │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── python │ │ ├── Cargo.toml │ │ ├── pyproject.toml │ │ └── src │ │ └── lib.rs ├── workspace-inverted-order │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── check_installed │ │ └── check_installed.py │ ├── path-dep-with-root │ │ ├── Cargo.toml │ │ ├── README.md │ │ ├── pyproject.toml │ │ └── src │ │ │ └── lib.rs │ ├── pyproject.toml │ └── src │ │ └── lib.rs ├── workspace │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Readme.md │ └── py │ │ ├── Cargo.toml │ │ ├── pyproject.toml │ │ └── src │ │ └── main.rs ├── workspace_with_path_dep │ ├── Cargo.lock │ ├── Cargo.toml │ ├── dont_include_in_sdist │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ ├── generic_lib │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── python │ │ ├── Cargo.toml │ │ ├── pyproject.toml │ │ └── src │ │ │ └── lib.rs │ └── transitive_lib │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs └── wrong-python-source │ ├── Cargo.lock │ ├── Cargo.toml │ ├── pyproject.toml │ ├── python │ └── run_this │ │ └── __init__.py │ └── src │ ├── bin │ └── run_this.rs │ └── lib.rs ├── test-data ├── Readme.md └── py.exe ├── test-dockerfile.sh └── tests ├── cli.rs ├── cmd ├── build.stderr ├── build.stdout ├── build.toml ├── develop.stderr ├── develop.stdout ├── develop.toml ├── generate-ci.stderr ├── generate-ci.stdout ├── generate-ci.toml ├── init.stderr ├── init.stdout ├── init.toml ├── list-python.stderr ├── list-python.stdout ├── list-python.toml ├── maturin.stderr ├── maturin.stdout ├── maturin.toml ├── new.stderr ├── new.stdout ├── new.toml ├── publish.stderr ├── publish.stdout ├── publish.toml ├── sdist.stderr ├── sdist.stdout ├── sdist.toml ├── upload.stderr ├── upload.stdout └── upload.toml ├── common ├── develop.rs ├── errors.rs ├── integration.rs ├── mod.rs └── other.rs ├── emscripten_runner.js ├── manylinux_compliant.sh ├── manylinux_incompliant.sh └── run.rs /.cirrus.yml: -------------------------------------------------------------------------------- 1 | env: 2 | RUST_BACKTRACE: 1 3 | CARGO_INCREMENTAL: 0 4 | CARGO_TERM_COLOR: always 5 | CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse 6 | 7 | build_and_test: 8 | &BUILD_AND_TEST # only run tasks on pull request or github merge queue branches 9 | only_if: $CIRRUS_BRANCH =~ 'gh-readonly-queue/.*' || $CIRRUS_PR != "" 10 | setup_script: 11 | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable 12 | - rustup target add wasm32-wasip1 13 | - python3 -m pip install --upgrade cffi virtualenv 14 | build_script: 15 | - cargo build 16 | test_script: 17 | - cargo test 18 | 19 | freebsd_task: 20 | name: Test (x86_64 FreeBSD) 21 | freebsd_instance: 22 | image_family: freebsd-14-2 23 | env: 24 | PATH: $HOME/.cargo/bin:$PATH 25 | target_cache: 26 | folder: target 27 | fingerprint_script: 28 | - echo $CIRRUS_OS 29 | - cat Cargo.lock 30 | install_script: 31 | - pkg install -y bash git python 32 | - python3 -m ensurepip 33 | <<: *BUILD_AND_TEST 34 | -------------------------------------------------------------------------------- /.codespellrc: -------------------------------------------------------------------------------- 1 | [codespell] 2 | ignore-words-list = crate,socio-economic 3 | skip = ./.git,./target,./test-crates/venvs,./guide/book 4 | -------------------------------------------------------------------------------- /.config/nextest.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | # Terminate slow tests after 30 minutes 3 | slow-timeout = { period = "60s", terminate-after = 30 } 4 | 5 | [[profile.default.overrides]] 6 | # See https://nexte.st/book/threads-required.html 7 | filter = 'test(/_uniffi_/)' 8 | threads-required = "num-cpus" 9 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maturin", 3 | "image": "mcr.microsoft.com/devcontainers/rust:bullseye", 4 | "postCreateCommand": "bash .devcontainer/post_create.sh", 5 | "customizations": { 6 | "vscode": { 7 | "extensions": [ 8 | "ms-python.black-formatter", 9 | "rust-lang.rust-analyzer", 10 | "charliermarsh.ruff" 11 | ], 12 | "settings": { 13 | "editor.formatOnSave": true 14 | } 15 | } 16 | }, 17 | "features": { 18 | "ghcr.io/devcontainers/features/sshd:1": { 19 | "version": "latest" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.devcontainer/post_create.sh: -------------------------------------------------------------------------------- 1 | set -euxo pipefail 2 | 3 | sudo apt-get update 4 | sudo apt-get install -y python3-dev python3-pip python3-venv libclang-dev 5 | sudo python3 -m pip install cffi virtualenv pipx 6 | 7 | pipx ensurepath 8 | pipx install uniffi-bindgen 9 | pipx install cargo-deny 10 | 11 | rustup target add wasm32-wasip1 12 | curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin 13 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.pytest_cache 2 | **/.tox 3 | **/__pycache__ 4 | **/target 5 | **/venv* 6 | .dockerignore 7 | .git 8 | .idea 9 | .travis.yml 10 | .venv 11 | Dockerfile* 12 | appveyor.yml 13 | ci 14 | sysconfig 15 | test-crates 16 | test-data 17 | test-dockerfile.sh 18 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: messense 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug Report 2 | description: Create a bug report 3 | labels: [bug] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thank you for taking the time to fill out this bug report! 9 | Please fill out the form below... 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: Bug Description 14 | description: Please provide a clear and concise description of what the bug is. 15 | placeholder: The bug is... 16 | validations: 17 | required: true 18 | - type: input 19 | id: maturin_version 20 | attributes: 21 | label: Your maturin version (`maturin --version`) 22 | placeholder: ex. 0.14.1 23 | validations: 24 | required: true 25 | - type: input 26 | id: py_version 27 | attributes: 28 | label: Your Python version (`python -V`) 29 | placeholder: ex. Python 3.10.0 30 | validations: 31 | required: true 32 | - type: input 33 | id: pip_version 34 | attributes: 35 | label: Your pip version (`pip -V`) 36 | placeholder: ex. pip 21.1.3 37 | validations: 38 | required: true 39 | - type: dropdown 40 | id: bindings 41 | attributes: 42 | label: What bindings you're using 43 | options: 44 | - "pyo3" 45 | - "cffi" 46 | - "uniffi" 47 | - "bin" 48 | validations: 49 | required: false 50 | - type: checkboxes 51 | id: cargo-build 52 | attributes: 53 | label: Does `cargo build` work? 54 | options: 55 | - label: Yes, it works 56 | required: false 57 | - type: checkboxes 58 | id: windows-unix-path 59 | attributes: 60 | label: If on windows, have you checked that you aren't accidentally using unix path (those with the forward slash `/`)? 61 | options: 62 | - label: "Yes" 63 | required: false 64 | - type: textarea 65 | id: reproduce 66 | attributes: 67 | label: Steps to Reproduce 68 | description: Please list the exact steps required to reproduce your error with all command output and if possible with a repository. Please run maturin with `RUST_LOG=maturin=debug` being set, e.g. `RUST_LOG=maturin=debug maturin build` and share the output, either in a codeblock or as a [gist](https://gist.github.com/) 69 | placeholder: | 70 | 1. 71 | 2. 72 | 3. 73 | validations: 74 | required: true 75 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: ❓ Question 4 | url: https://github.com/PyO3/maturin/discussions 5 | about: Ask and answer questions about maturin on Discussions 6 | - name: 🔧 Troubleshooting 7 | url: https://github.com/PyO3/maturin/discussions 8 | about: For troubleshooting help, see the Discussions 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💡 Feature request 3 | about: Suggest an idea for this project 4 | labels: [enhancement] 5 | --- 6 | 7 | 15 | -------------------------------------------------------------------------------- /.github/bors.toml: -------------------------------------------------------------------------------- 1 | delete_merged_branches = true 2 | required_approvals = 0 3 | use_codeowners = false 4 | status = [ 5 | # GitHub Actions 6 | "conclusion", 7 | # Cirrus CI 8 | "Test (x86_64 FreeBSD)", 9 | "Test (arm64 macOS)", 10 | "Test (arm64 Linux)" 11 | ] 12 | timeout_sec = 21600 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "cargo" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | groups: 13 | crates-io: 14 | patterns: 15 | - "*" 16 | 17 | - package-ecosystem: "github-actions" 18 | directory: "/" 19 | schedule: 20 | interval: "monthly" 21 | -------------------------------------------------------------------------------- /.github/workflows/clear-cache.yml: -------------------------------------------------------------------------------- 1 | name: Clear Actions Cache 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | permissions: 7 | actions: write 8 | 9 | jobs: 10 | clear-cache: 11 | name: Clean Cache 12 | runs-on: ubuntu-latest 13 | env: 14 | GH_TOKEN: ${{ github.token }} 15 | steps: 16 | - name: Clear cache 17 | run: | 18 | gh cache delete --all --repo "$GITHUB_REPOSITORY" 19 | echo "cache cleared" 20 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: [ 'v*' ] 8 | 9 | jobs: 10 | publish-docker: 11 | name: Publish Docker Images 12 | runs-on: ubuntu-latest 13 | environment: 14 | name: Docker Hub 15 | url: https://ghcr.io/pyo3/maturin 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: dorny/paths-filter@v3 19 | id: changes 20 | with: 21 | filters: | 22 | changed: 23 | - 'Cargo.toml' 24 | - 'Cargo.lock' 25 | - 'src/**' 26 | - 'Dockerfile' 27 | - '.github/workflows/docker.yml' 28 | - '.dockerignore' 29 | - name: Setup QEMU 30 | if: ${{ steps.changes.outputs.changed == 'true' || startsWith(github.ref, 'refs/tags/') }} 31 | uses: dbhi/qus/action@main 32 | - uses: docker/setup-buildx-action@v3 33 | if: ${{ steps.changes.outputs.changed == 'true' || startsWith(github.ref, 'refs/tags/') }} 34 | - uses: docker/metadata-action@v5 35 | if: ${{ steps.changes.outputs.changed == 'true' || startsWith(github.ref, 'refs/tags/') }} 36 | id: meta 37 | with: 38 | images: ghcr.io/pyo3/maturin 39 | - name: Login to GitHub Container Registry 40 | if: ${{ steps.changes.outputs.changed == 'true' || startsWith(github.ref, 'refs/tags/') }} 41 | uses: docker/login-action@v3 42 | with: 43 | registry: ghcr.io 44 | username: ${{ github.actor }} 45 | password: ${{ secrets.GITHUB_TOKEN }} 46 | - name: Build and push 47 | if: ${{ steps.changes.outputs.changed == 'true' || startsWith(github.ref, 'refs/tags/') }} 48 | uses: docker/build-push-action@v6 49 | with: 50 | context: . 51 | platforms: linux/amd64,linux/arm64 52 | push: true 53 | tags: ${{ steps.meta.outputs.tags }} 54 | labels: ${{ steps.meta.outputs.labels }} 55 | # https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#registry-cache 56 | cache-from: type=registry,ref=ghcr.io/pyo3/maturin:buildcache 57 | cache-to: type=registry,ref=ghcr.io/pyo3/maturin:buildcache,mode=max 58 | -------------------------------------------------------------------------------- /.github/workflows/downstream.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | repository: 5 | required: true 6 | type: string 7 | manifest-dir: 8 | required: true 9 | type: string 10 | 11 | jobs: 12 | sdist: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Sccache Setup 17 | uses: mozilla-actions/sccache-action@v0.0.9 18 | with: 19 | version: "v0.10.0" 20 | - name: Build maturin 21 | env: 22 | RUST_BACKTRACE: "1" 23 | SCCACHE_GHA_ENABLED: "true" 24 | RUSTC_WRAPPER: "sccache" 25 | run: cargo build 26 | - uses: actions/checkout@v4 27 | with: 28 | repository: ${{ inputs.repository }} 29 | submodules: "recursive" 30 | path: downstream 31 | - name: maturin sdist 32 | working-directory: downstream 33 | run: | 34 | ../target/debug/maturin sdist --manifest-path ${{ inputs.manifest-dir }}/Cargo.toml -o target/sdist 35 | - name: Build from sdist 36 | working-directory: downstream 37 | run: | 38 | ../target/debug/maturin build --manifest-path ${{ inputs.manifest-dir }}/Cargo.toml 39 | -------------------------------------------------------------------------------- /.github/workflows/update-auditwheel.yml: -------------------------------------------------------------------------------- 1 | name: Update auditwheel policies 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | # Run every week 7 | - cron: '0 0 * * 0' 8 | 9 | permissions: # added using https://github.com/step-security/secure-workflows 10 | contents: read 11 | 12 | jobs: 13 | update: 14 | permissions: 15 | contents: write # for peter-evans/create-pull-request to create branch 16 | pull-requests: write # for peter-evans/create-pull-request to create a PR 17 | name: Update auditwheel policies 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Fetch latest policy files 22 | run: | 23 | curl https://raw.githubusercontent.com/pypa/auditwheel/main/src/auditwheel/policy/manylinux-policy.json > src/auditwheel/manylinux-policy.json 24 | curl https://raw.githubusercontent.com/pypa/auditwheel/main/src/auditwheel/policy/musllinux-policy.json > src/auditwheel/musllinux-policy.json 25 | - name: Create Pull Request 26 | uses: peter-evans/create-pull-request@v7 27 | with: 28 | delete-branch: true 29 | add-paths: | 30 | src/auditwheel/*.json 31 | title: 'Update manylinux/musllinux policies to the latest main' 32 | commit-message: 'Update manylinux/musllinux policies to the latest main' 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | venv*/ 3 | .venv/ 4 | .pytest_cache/ 5 | .tox/ 6 | *.o 7 | *.so 8 | *.py[cdo] 9 | __pycache__/ 10 | *.egg-info/ 11 | *.egg 12 | dist/ 13 | build 14 | dist 15 | tags 16 | test-crates/wheels/ 17 | test-crates/targets/ 18 | test-crates/venvs/ 19 | node_modules 20 | .idea 21 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # run all hooks with: 2 | # pre-commit run --hook-stage manual --all 3 | ci: 4 | skip: 5 | # pre-commit.ci doesn't have Rust installed 6 | - cargo-fmt 7 | - cargo-deny 8 | 9 | repos: 10 | - repo: local 11 | hooks: 12 | - id: cargo-fmt # rustup component add rustfmt 13 | name: cargo fmt 14 | entry: cargo fmt --all -- 15 | language: system 16 | types: [rust] 17 | pass_filenames: false 18 | 19 | - id: cargo-deny # cargo install --locked cargo-deny 20 | name: cargo deny 21 | entry: cargo deny --all-features check -- 22 | language: system 23 | pass_filenames: false 24 | 25 | - id: cargo-check 26 | name: cargo check 27 | entry: cargo check --all-features --all-targets -- 28 | language: system 29 | pass_filenames: false 30 | types: [rust] 31 | stages: [manual] # because it's slow 32 | 33 | - id: cargo-clippy # rustup component add clippy 34 | name: cargo clippy 35 | entry: cargo clippy --tests --all-features -- -D warnings 36 | language: system 37 | pass_filenames: false 38 | types: [rust] 39 | stages: [manual] # because it's slow 40 | - repo: https://github.com/pre-commit/pre-commit-hooks 41 | rev: v5.0.0 42 | hooks: 43 | - id: check-yaml 44 | - id: check-toml 45 | - id: end-of-file-fixer 46 | exclude: | 47 | (?x)( 48 | (^sysconfig/)| 49 | (.*\.stdout) 50 | ) 51 | - id: trailing-whitespace 52 | exclude: | 53 | (?x)( 54 | (^sysconfig/)| 55 | (.*\.stdout) 56 | ) 57 | - id: mixed-line-ending 58 | - repo: https://github.com/astral-sh/ruff-pre-commit 59 | rev: v0.11.11 60 | hooks: 61 | - id: ruff-format 62 | - id: ruff 63 | - repo: https://github.com/pre-commit/mirrors-mypy 64 | rev: v1.15.0 65 | hooks: 66 | - id: mypy 67 | entry: mypy maturin/ 68 | pass_filenames: false 69 | - repo: https://github.com/codespell-project/codespell 70 | rev: v2.4.1 71 | hooks: 72 | - id: codespell 73 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # x86_64 base 2 | FROM quay.io/pypa/manylinux2014_x86_64 AS base-amd64 3 | # x86_64 builder 4 | FROM --platform=$BUILDPLATFORM ghcr.io/rust-cross/rust-musl-cross:x86_64-musl AS builder-amd64 5 | 6 | # aarch64 base 7 | FROM quay.io/pypa/manylinux2014_aarch64 AS base-arm64 8 | # aarch64 cross compile builder 9 | FROM --platform=$BUILDPLATFORM ghcr.io/rust-cross/rust-musl-cross:aarch64-musl AS builder-arm64 10 | 11 | ARG TARGETARCH 12 | FROM builder-$TARGETARCH AS builder 13 | 14 | ENV PATH=/root/.cargo/bin:$PATH 15 | 16 | # Compile dependencies only for build caching 17 | ADD Cargo.toml /maturin/Cargo.toml 18 | ADD Cargo.lock /maturin/Cargo.lock 19 | RUN --mount=type=cache,target=/root/.cargo/git \ 20 | --mount=type=cache,target=/root/.cargo/registry \ 21 | --mount=type=cache,target=/maturin/target,sharing=locked \ 22 | mkdir /maturin/src && \ 23 | touch /maturin/src/lib.rs && \ 24 | echo 'fn main() { println!("Dummy") }' > /maturin/src/main.rs && \ 25 | cargo rustc --target $CARGO_BUILD_TARGET --bin maturin --manifest-path /maturin/Cargo.toml --release --features password-storage -- -C link-arg=-s 26 | 27 | ADD . /maturin/ 28 | 29 | # Manually update the timestamps as ADD keeps the local timestamps and cargo would then believe the cache is fresh 30 | RUN touch /maturin/src/lib.rs /maturin/src/main.rs 31 | 32 | RUN --mount=type=cache,target=/root/.cargo/git \ 33 | --mount=type=cache,target=/root/.cargo/registry \ 34 | --mount=type=cache,target=/maturin/target,sharing=locked \ 35 | cargo rustc --target $CARGO_BUILD_TARGET --bin maturin --manifest-path /maturin/Cargo.toml --release --features password-storage -- -C link-arg=-s \ 36 | && mv /maturin/target/$CARGO_BUILD_TARGET/release/maturin /usr/bin/maturin 37 | 38 | FROM base-$TARGETARCH 39 | 40 | ENV PATH=/root/.cargo/bin:$PATH 41 | # Add all supported python versions 42 | ENV PATH=/opt/python/cp39-cp39/bin:/opt/python/cp310-cp310/bin:/opt/python/cp311-cp311/bin:/opt/python/cp312-cp312/bin:/opt/python/cp313-cp313/bin/:/opt/python/cp313-cp313t/bin/:$PATH 43 | # Otherwise `cargo new` errors 44 | ENV USER=root 45 | 46 | RUN curl --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \ 47 | && yum install -y libffi-devel openssh-clients \ 48 | && python3.8 -m pip install --no-cache-dir cffi \ 49 | && python3.9 -m pip install --no-cache-dir cffi \ 50 | && python3.10 -m pip install --no-cache-dir cffi \ 51 | && python3.11 -m pip install --no-cache-dir cffi \ 52 | && python3.12 -m pip install --no-cache-dir cffi \ 53 | && mkdir /io 54 | 55 | COPY --from=builder /usr/bin/maturin /usr/bin/maturin 56 | 57 | WORKDIR /io 58 | 59 | ENTRYPOINT ["/usr/bin/maturin"] 60 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include Cargo.toml Cargo.lock 2 | include README.md 3 | include license-apache license-mit 4 | recursive-include src *.rs *.py 5 | recursive-include src/auditwheel *.json 6 | recursive-include src/python_interpreter *.py *.json 7 | recursive-include src/templates *.j2 8 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | msrv = "1.74.0" 2 | 3 | disallowed-types = [ 4 | "std::fs::DirEntry", 5 | "std::fs::File", 6 | "std::fs::OpenOptions", 7 | "std::fs::ReadDir", 8 | ] 9 | 10 | disallowed-methods = [ 11 | "std::fs::canonicalize", 12 | "std::fs::copy", 13 | "std::fs::create_dir", 14 | "std::fs::create_dir_all", 15 | "std::fs::hard_link", 16 | "std::fs::metadata", 17 | "std::fs::read", 18 | "std::fs::read_dir", 19 | "std::fs::read_link", 20 | "std::fs::read_to_string", 21 | "std::fs::remove_dir", 22 | "std::fs::remove_dir_all", 23 | "std::fs::remove_file", 24 | "std::fs::rename", 25 | "std::fs::set_permissions", 26 | "std::fs::soft_link", 27 | "std::fs::symlink_metadata", 28 | "std::fs::write", 29 | ] 30 | -------------------------------------------------------------------------------- /guide/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /guide/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["PyO3 Project and Contributors"] 3 | language = "en" 4 | src = "src" 5 | title = "Maturin User Guide" 6 | 7 | [output.html] 8 | additional-css = ["tweak.css"] 9 | git-repository-url = "https://github.com/PyO3/maturin/tree/main/guide" 10 | edit-url-template = "https://github.com/PyO3/maturin/edit/main/guide/{path}" 11 | -------------------------------------------------------------------------------- /guide/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [Introduction](index.md) 4 | 5 | --- 6 | 7 | - [Installation](./installation.md) 8 | - [Tutorial](./tutorial.md) 9 | - [Project Layout](./project_layout.md) 10 | - [Bindings](./bindings.md) 11 | - [Python Metadata](./metadata.md) 12 | - [Configuration](./config.md) 13 | - [Environment Variables](./environment-variables.md) 14 | - [Local Development](./local_development.md) 15 | - [Import Hook](./import_hook.md) 16 | - [Distribution](./distribution.md) 17 | - [Sphinx Integration](./sphinx.md) 18 | 19 | --- 20 | 21 | - [Migration Guide](./migration.md) 22 | - [Changelog](./changelog.md) 23 | 24 | --- 25 | 26 | - [Contributing](./contributing.md) 27 | - [Platform Support](./platform_support.md) 28 | -------------------------------------------------------------------------------- /guide/src/assets/sponsors/astral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/guide/src/assets/sponsors/astral.png -------------------------------------------------------------------------------- /guide/src/assets/sponsors/bytewax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/guide/src/assets/sponsors/bytewax.png -------------------------------------------------------------------------------- /guide/src/assets/sponsors/frontend-masters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/guide/src/assets/sponsors/frontend-masters.png -------------------------------------------------------------------------------- /guide/src/assets/sponsors/prefect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/guide/src/assets/sponsors/prefect.png -------------------------------------------------------------------------------- /guide/src/assets/sponsors/pydantic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/guide/src/assets/sponsors/pydantic.png -------------------------------------------------------------------------------- /guide/src/assets/sponsors/quansightlabs.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/guide/src/assets/sponsors/quansightlabs.jpeg -------------------------------------------------------------------------------- /guide/src/assets/sponsors/rerun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/guide/src/assets/sponsors/rerun.png -------------------------------------------------------------------------------- /guide/src/assets/sponsors/sentry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/guide/src/assets/sponsors/sentry.png -------------------------------------------------------------------------------- /guide/src/assets/sponsors/tsy-capital.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/guide/src/assets/sponsors/tsy-capital.png -------------------------------------------------------------------------------- /guide/src/changelog.md: -------------------------------------------------------------------------------- 1 | {{#include ../../Changelog.md}} 2 | -------------------------------------------------------------------------------- /guide/src/environment-variables.md: -------------------------------------------------------------------------------- 1 | # Environment Variables 2 | 3 | Maturin reads a number of environment variables which you can use to configure the build process. 4 | Here is a list of all environment variables that are read by maturin: 5 | 6 | ## Cargo environment variables 7 | 8 | See [environment variables Cargo reads](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-reads) 9 | 10 | ## Python environment variables 11 | 12 | * `VIRTUAL_ENV`: Path to a Python virtual environment 13 | * `CONDA_PREFIX`: Path to a conda environment 14 | * `MATURIN_PYTHON_SYSCONFIGDATA_DIR`: Path to a directory containing a `sysconfigdata*.py` file 15 | * `_PYTHON_SYSCONFIGDATA_NAME`: Name of a `sysconfigdata*.py` file 16 | * `MATURIN_PYPI_TOKEN`: PyPI token for uploading wheels 17 | * `MATURIN_PASSWORD`: PyPI password for uploading wheels 18 | * `MATURIN_PEP517_USE_BASE_PYTHON`: Use base Python executable instead of venv Python executable in PEP 517 build to avoid unnecessary rebuilds, should not be set when the sdist build requires packages installed in venv. 19 | 20 | ## `pyo3` environment variables 21 | 22 | * `PYO3_CROSS_PYTHON_VERSION`: Python version to use for cross compilation 23 | * `PYO3_CROSS_LIB_DIR`: This variable can be set to the directory containing the target's libpython DSO and the associated `_sysconfigdata*.py` file for Unix-like targets, or the Python DLL import libraries for the Windows target.This variable can be set to the directory containing the target's libpython DSO and the associated _sysconfigdata*.py file for Unix-like targets, or the Python DLL import libraries for the Windows target. 24 | * `PYO3_CONFIG_FILE`: Path to a [pyo3 config file](https://pyo3.rs/latest/building_and_distribution.html#advanced-config-files) 25 | 26 | ## Networking environment variables 27 | 28 | * `HTTP_PROXY` / `HTTPS_PROXY`: Proxy to use for HTTP/HTTPS requests 29 | * `REQUESTS_CA_BUNDLE` / `CURL_CA_BUNDLE`: Path to a CA bundle to use for HTTPS requests 30 | 31 | ## Other environment variables 32 | 33 | * `MACOSX_DEPLOYMENT_TARGET`: The minimum macOS version to target 34 | * `SOURCE_DATE_EPOCH`: The time to use for the timestamp in the wheel metadata 35 | * `MATURIN_EMSCRIPTEN_VERSION`: The version of emscripten to use for emscripten builds 36 | * `MATURIN_NO_MISSING_BUILD_BACKEND_WARNING`: Suppress missing build backend warning 37 | * `MATURIN_USE_XWIN`: Set to `1` to force to use `xwin` for cross compiling even on Windows that supports native compilation 38 | * `TARGET_SYSROOT`: The sysroot to use for auditwheel wheel when cross compiling 39 | * `ARCHFLAGS`: Flags to control the architecture of the build on macOS, for example you can use `ARCHFLAGS="-arch x86_64 -arch arm64"` to build universal2 wheels 40 | -------------------------------------------------------------------------------- /guide/src/index.md: -------------------------------------------------------------------------------- 1 | # Maturin User Guide 2 | 3 | Welcome to the maturin user guide! It contains examples and documentation to explain all of maturin's use cases in detail. 4 | 5 | Please choose from the chapters on the left to jump to individual topics, or continue below to start with maturin's README. 6 | 7 | ## Sponsors 8 | 9 | Development of maturin is made possible by the following sponsors: 10 | 11 |
12 |
13 | 14 | Astral 15 | Astral 16 | 17 |
18 |
19 | 20 | Bytewax 21 | Bytewax 22 | 23 |
24 |
25 | 26 | Frontend Masters 27 | Frontend Masters 28 | 29 |
30 |
31 | 32 | Prefect 33 | Prefect 34 | 35 |
36 |
37 | 38 | Pydantic 39 | Pydantic 40 | 41 |
42 |
43 | 44 | Quansight Labs 45 | Quansight Labs 46 | 47 |
48 |
49 | 50 | Rerun 51 | Rerun 52 | 53 |
54 |
55 | 56 | Sentry 57 | Sentry 58 | 59 |
60 |
61 | 62 | TSY Capital 63 | TSY Capital 64 | 65 |
66 |
67 | 68 | And many more who kindly sponsor @messense on [GitHub Sponsors](https://github.com/sponsors/messense#sponsors). 69 | 70 | {{#include ../../README.md}} 71 | -------------------------------------------------------------------------------- /guide/src/platform_support.md: -------------------------------------------------------------------------------- 1 | # Platform Support 2 | 3 | Being built on cargo and rustc, maturin is limited by [rust's platform support](https://doc.rust-lang.org/nightly/rustc/platform-support.html). 4 | 5 | ## Automated tests 6 | 7 | On GitHub actions, windows, macOS and linux are tested, all 8 | on 64-bit x86. FreeBSD is also tested though Cirrus CI, but might get removed at 9 | some point. Since CI is very time intensive to maintain, I'd like to stick to 10 | GitHub action and these three platforms. 11 | 12 | ## Releases 13 | 14 | The following targets are built into wheels and downloadable binaries: 15 | 16 | * Windows: 32-bit and 64-bit x86 as well as arm64 17 | * Linux: x86, x86_64, armv7, aarch64 and ppc64le (musl), as well as s390x (gnu) 18 | * macOS: x86_64 and aarch64 19 | 20 | ## Other Operating Systems 21 | 22 | It should be possible to build maturin and for maturin to build wheels on other platforms supported by rust. 23 | To add a new os, add it in target.rs and, if it doesn't behave like the other unixes, in 24 | `PythonInterpreter::get_tag`. Please also submit the output of `python -m sysconfig` as a file in the `sysconfig` folder. 25 | It's ok to edit setup.py to deactivate default features so `pip install` works, but new platforms should not 26 | require complex workaround in `compile.rs`. 27 | 28 | ## Architectures 29 | 30 | All architectures included in manylinux (aarch64, armv7l, ppc64le, ppc64, i686, x86_64, s390x) are supported. 31 | I'm not sure whether it makes sense to allow architectures that aren't even 32 | supported by [manylinux](https://github.com/pypa/manylinux). 33 | 34 | ## Python Support 35 | 36 | CPython 3.8 to 3.10 are supported and tested on CI, though the entire 3.x series should work. 37 | This will be changed as new python versions are released and others have their end of life. 38 | 39 | PyPy 3.6 and later also works, as does GraalPy 23.0 and later. 40 | 41 | ## Manylinux/Musllinux 42 | 43 | `manylinux2014` and its newer versions as well as `musllinux_1_1` and its newer versions 44 | are supported. 45 | 46 | Since Rust and the manylinux project drop support for old manylinux/musllinux versions sometimes, 47 | after maturin 1.0 manylinux version bumps will be minor versions rather than major versions. 48 | -------------------------------------------------------------------------------- /guide/tweak.css: -------------------------------------------------------------------------------- 1 | .sponsors { 2 | display: flex; 3 | justify-content: left; 4 | flex-wrap: wrap; 5 | align-items: center; 6 | margin: 1rem 0; 7 | } 8 | 9 | .sponsors > div { 10 | text-align: center; 11 | width: 25%; 12 | padding-bottom: 20px; 13 | } 14 | 15 | .sponsors span { 16 | display: block; 17 | } 18 | -------------------------------------------------------------------------------- /license-mit: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 konstin 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /maturin/__main__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os 4 | import sys 5 | from pathlib import Path 6 | import sysconfig 7 | from typing import Optional 8 | 9 | 10 | def get_maturin_path() -> Optional[Path]: 11 | SCRIPT_NAME = "maturin" 12 | 13 | def script_dir(scheme: str) -> str: 14 | return sysconfig.get_path("scripts", scheme) 15 | 16 | def script_exists(dir: str) -> bool: 17 | for _, _, files in os.walk(dir): 18 | for f in files: 19 | name, *_ = os.path.splitext(f) 20 | if name == SCRIPT_NAME: 21 | return True 22 | 23 | return False 24 | 25 | paths = list( 26 | filter( 27 | script_exists, 28 | filter(os.path.exists, map(script_dir, sysconfig.get_scheme_names())), 29 | ) 30 | ) 31 | 32 | if paths: 33 | return Path(paths[0]) / SCRIPT_NAME 34 | 35 | return None 36 | 37 | 38 | if __name__ == "__main__": 39 | maturin = get_maturin_path() 40 | if maturin is None: 41 | print("Unable to find `maturin` script") 42 | exit(1) 43 | 44 | if sys.platform == "win32": 45 | import subprocess 46 | 47 | code = subprocess.call([str(maturin)] + sys.argv[1:]) 48 | sys.exit(code) 49 | else: 50 | os.execv(maturin, [str(maturin)] + sys.argv[1:]) 51 | -------------------------------------------------------------------------------- /maturin/bootstrap.py: -------------------------------------------------------------------------------- 1 | """Support installing rust before compiling (bootstrapping) maturin. 2 | 3 | Installing a package that uses maturin as build backend on a platform without maturin 4 | binaries, we install rust in a cache directory if the user doesn't have a rust 5 | installation already. Since this bootstrapping requires more dependencies but is only 6 | required if rust is missing, we check if cargo is present before requesting those 7 | dependencies. 8 | 9 | https://setuptools.pypa.io/en/stable/build_meta.html#dynamic-build-dependencies-and-other-build-meta-tweaks 10 | """ 11 | 12 | from __future__ import annotations 13 | 14 | import os 15 | import shutil 16 | from typing import Any 17 | 18 | # noinspection PyUnresolvedReferences 19 | from setuptools.build_meta import * # noqa:F403 20 | from setuptools.build_meta import ( 21 | get_requires_for_build_sdist as _orig_get_requires_for_build_sdist, 22 | ) 23 | from setuptools.build_meta import ( 24 | get_requires_for_build_wheel as _orig_get_requires_for_build_wheel, 25 | ) 26 | 27 | 28 | def get_requires_for_build_wheel(config_settings: dict[str, Any] | None = None) -> list[str]: 29 | reqs = _orig_get_requires_for_build_wheel() 30 | if not os.environ.get("MATURIN_NO_INSTALL_RUST") and not shutil.which("cargo"): 31 | reqs.append("puccinialin>=0.1,<0.2") 32 | return reqs 33 | 34 | 35 | def get_requires_for_build_sdist(config_settings: dict[str, Any] | None = None) -> list[str]: 36 | reqs = _orig_get_requires_for_build_sdist() 37 | if not os.environ.get("MATURIN_NO_INSTALL_RUST") and not shutil.which("cargo"): 38 | reqs.append("puccinialin>=0.1,<0.2") 39 | return reqs 40 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "guide/book/" 3 | command = "curl -L https://github.com/rust-lang/mdBook/releases/download/v0.4.43/mdbook-v0.4.43-x86_64-unknown-linux-musl.tar.gz | tar xvz && ./mdbook build guide" 4 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | # Workaround to bootstrap maturin on non-manylinux platforms 2 | [build-system] 3 | requires = [ 4 | "setuptools", 5 | "tomli>=1.1.0 ; python_version<'3.11'", 6 | "setuptools-rust>=1.11.0", 7 | ] 8 | backend-path = ["maturin"] 9 | build-backend = "bootstrap" 10 | 11 | [project] 12 | name = "maturin" 13 | description = "Build and publish crates with pyo3, cffi and uniffi bindings as well as rust binaries as python packages" 14 | authors = [{ name = "konstin", email = "konstin@mailbox.org" }] 15 | readme = { file = "README.md", content-type = "text/markdown" } 16 | requires-python = ">=3.7" 17 | license = { text = "MIT OR Apache-2.0" } 18 | classifiers = [ 19 | "Topic :: Software Development :: Build Tools", 20 | "Programming Language :: Rust", 21 | "Programming Language :: Python :: Implementation :: CPython", 22 | "Programming Language :: Python :: Implementation :: PyPy", 23 | ] 24 | dependencies = ["tomli>=1.1.0 ; python_version<'3.11'"] 25 | dynamic = ["version"] 26 | 27 | [project.optional-dependencies] 28 | zig = ["ziglang>=0.10.0,<0.13.0"] 29 | patchelf = ["patchelf"] 30 | 31 | [project.urls] 32 | "Source Code" = "https://github.com/PyO3/maturin" 33 | Issues = "https://github.com/PyO3/maturin/issues" 34 | Documentation = "https://maturin.rs" 35 | Changelog = "https://maturin.rs/changelog.html" 36 | 37 | [tool.setuptools] 38 | packages = ["maturin"] 39 | 40 | [tool.maturin] 41 | bindings = "bin" 42 | 43 | [tool.black] 44 | target-version = ['py37'] 45 | extend-exclude = ''' 46 | # Ignore cargo-generate templates 47 | ^/src/templates 48 | ''' 49 | 50 | [tool.ruff] 51 | line-length = 120 52 | target-version = "py37" 53 | 54 | [tool.mypy] 55 | disallow_untyped_defs = true 56 | disallow_incomplete_defs = true 57 | warn_no_return = true 58 | ignore_missing_imports = true 59 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # maturin is self bootstrapping, however on platforms like FreeBSD that aren't 2 | # manylinux/musllinux, pip will try installing maturin from the source distribution. 3 | # That source distribution obviously can't depend on maturin, so we're using 4 | # the always available setuptools. 5 | # 6 | # Note that this is really only a workaround for bootstrapping and not suited 7 | # for general purpose packaging, i.e. only building a wheel (as in 8 | # `python setup.py bdist_wheel`) and installing (as in 9 | # `pip install `) are supported. For creating a source distribution 10 | # for maturin itself use `maturin sdist`. 11 | 12 | import os 13 | import shlex 14 | import shutil 15 | 16 | try: 17 | import tomllib 18 | except ModuleNotFoundError: 19 | import tomli as tomllib 20 | from setuptools import setup 21 | 22 | from setuptools_rust import RustBin 23 | 24 | # Force the wheel to be platform specific 25 | # https://stackoverflow.com/a/45150383/3549270 26 | # There's also the much more concise solution in 27 | # https://stackoverflow.com/a/53463910/3549270, 28 | # but that would require python-dev 29 | try: 30 | # noinspection PyPackageRequirements,PyUnresolvedReferences 31 | from wheel.bdist_wheel import bdist_wheel as _bdist_wheel 32 | 33 | # noinspection PyPep8Naming,PyAttributeOutsideInit 34 | class bdist_wheel(_bdist_wheel): 35 | def finalize_options(self): 36 | _bdist_wheel.finalize_options(self) 37 | self.root_is_pure = False 38 | 39 | except ImportError: 40 | bdist_wheel = None 41 | 42 | with open("Cargo.toml", "rb") as fp: 43 | version = tomllib.load(fp)["package"]["version"] 44 | 45 | # Use `--no-default-features` by default for a minimal build to support PEP 517. 46 | # `MATURIN_SETUP_ARGS` env var can be used to pass customized arguments to cargo. 47 | cargo_args = ["--no-default-features"] 48 | if os.getenv("MATURIN_SETUP_ARGS"): 49 | cargo_args = shlex.split(os.getenv("MATURIN_SETUP_ARGS", "")) 50 | 51 | if not os.environ.get("MATURIN_NO_INSTALL_RUST") and not shutil.which("cargo"): 52 | from puccinialin import setup_rust 53 | 54 | print("Rust not found, installing into a temporary directory") 55 | extra_env = setup_rust() 56 | env = {**os.environ, **extra_env} 57 | else: 58 | env = None 59 | 60 | setup( 61 | version=version, 62 | cmdclass={"bdist_wheel": bdist_wheel}, 63 | rust_extensions=[RustBin("maturin", args=cargo_args, cargo_manifest_args=["--locked"], env=env)], 64 | zip_safe=False, 65 | ) 66 | -------------------------------------------------------------------------------- /src/auditwheel/mod.rs: -------------------------------------------------------------------------------- 1 | mod audit; 2 | mod musllinux; 3 | pub mod patchelf; 4 | mod platform_tag; 5 | mod policy; 6 | mod repair; 7 | 8 | pub use audit::*; 9 | pub use platform_tag::PlatformTag; 10 | pub use policy::Policy; 11 | pub use repair::find_external_libs; 12 | -------------------------------------------------------------------------------- /src/auditwheel/musllinux-policy.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"name": "linux", 3 | "aliases": [], 4 | "priority": 0, 5 | "symbol_versions": {}, 6 | "lib_whitelist": [], 7 | "blacklist": {} 8 | }, 9 | {"name": "musllinux_1_1", 10 | "aliases": [], 11 | "priority": 100, 12 | "symbol_versions": { 13 | "i686": { 14 | }, 15 | "x86_64": { 16 | }, 17 | "aarch64": { 18 | }, 19 | "ppc64le": { 20 | }, 21 | "s390x": { 22 | }, 23 | "armv7l": { 24 | }, 25 | "riscv64": { 26 | } 27 | }, 28 | "lib_whitelist": ["libc.so", "libz.so.1"], 29 | "blacklist": { 30 | "libz.so.1": ["_dist_code", "_length_code", "_tr_align", "_tr_flush_block", "_tr_init", "_tr_stored_block", "_tr_tally", "bi_windup", "crc32_vpmsum", "crc_fold_512to32", "crc_fold_copy", "crc_fold_init", "deflate_copyright", "deflate_medium", "fill_window", "flush_pending", "gzflags", "inflate_copyright", "inflate_fast", "inflate_table", "longest_match", "slide_hash_sse", "static_ltree", "uncompress2", "x86_check_features", "x86_cpu_has_pclmul", "x86_cpu_has_sse2", "x86_cpu_has_sse42", "z_errmsg", "zcalloc", "zcfree"] 31 | }}, 32 | {"name": "musllinux_1_2", 33 | "aliases": [], 34 | "priority": 90, 35 | "symbol_versions": { 36 | "i686": { 37 | }, 38 | "x86_64": { 39 | }, 40 | "aarch64": { 41 | }, 42 | "ppc64le": { 43 | }, 44 | "s390x": { 45 | }, 46 | "armv7l": { 47 | }, 48 | "riscv64": { 49 | }, 50 | "loongarch64": { 51 | } 52 | }, 53 | "lib_whitelist": ["libc.so", "libz.so.1"], 54 | "blacklist": { 55 | "libz.so.1": ["_dist_code", "_length_code", "_tr_align", "_tr_flush_block", "_tr_init", "_tr_stored_block", "_tr_tally", "bi_windup", "crc32_vpmsum", "crc_fold_512to32", "crc_fold_copy", "crc_fold_init", "deflate_copyright", "deflate_medium", "fill_window", "flush_pending", "gzflags", "inflate_copyright", "inflate_fast", "inflate_table", "longest_match", "slide_hash_sse", "static_ltree", "uncompress2", "x86_check_features", "x86_cpu_has_pclmul", "x86_cpu_has_sse2", "x86_cpu_has_sse42", "z_errmsg", "zcalloc", "zcfree"] 56 | }} 57 | ] 58 | -------------------------------------------------------------------------------- /src/auditwheel/musllinux.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use fs_err as fs; 3 | use goblin::elf::Elf; 4 | use regex::Regex; 5 | use std::path::{Path, PathBuf}; 6 | use std::process::{Command, Stdio}; 7 | 8 | /// Find musl libc path from executable's ELF header 9 | pub fn find_musl_libc() -> Result> { 10 | let buffer = fs::read("/bin/ls")?; 11 | let elf = Elf::parse(&buffer)?; 12 | Ok(elf.interpreter.map(PathBuf::from)) 13 | } 14 | 15 | /// Read the musl version from libc library's output 16 | /// 17 | /// The libc library should output something like this to stderr:: 18 | /// 19 | /// musl libc (x86_64) 20 | /// Version 1.2.2 21 | /// Dynamic Program Loader 22 | pub fn get_musl_version(ld_path: impl AsRef) -> Result> { 23 | let ld_path = ld_path.as_ref(); 24 | let output = Command::new(ld_path) 25 | .stdout(Stdio::null()) 26 | .stderr(Stdio::piped()) 27 | .output()?; 28 | let stderr = std::str::from_utf8(&output.stderr)?; 29 | let expr = Regex::new(r"Version (\d+)\.(\d+)")?; 30 | if let Some(capture) = expr.captures(stderr) { 31 | let context = "Expected a digit"; 32 | let major = capture 33 | .get(1) 34 | .unwrap() 35 | .as_str() 36 | .parse::() 37 | .context(context)?; 38 | let minor = capture 39 | .get(2) 40 | .unwrap() 41 | .as_str() 42 | .parse::() 43 | .context(context)?; 44 | return Ok(Some((major, minor))); 45 | } 46 | Ok(None) 47 | } 48 | -------------------------------------------------------------------------------- /src/auditwheel/repair.rs: -------------------------------------------------------------------------------- 1 | use super::audit::AuditWheelError; 2 | use crate::auditwheel::Policy; 3 | use anyhow::Result; 4 | use lddtree::DependencyAnalyzer; 5 | use std::path::{Path, PathBuf}; 6 | 7 | /// Find external shared library dependencies 8 | #[allow(clippy::result_large_err)] 9 | pub fn find_external_libs( 10 | artifact: impl AsRef, 11 | policy: &Policy, 12 | sysroot: PathBuf, 13 | ld_paths: Vec, 14 | ) -> Result, AuditWheelError> { 15 | let dep_analyzer = DependencyAnalyzer::new(sysroot).library_paths(ld_paths); 16 | let deps = dep_analyzer 17 | .analyze(artifact) 18 | .map_err(AuditWheelError::DependencyAnalysisError)?; 19 | let mut ext_libs = Vec::new(); 20 | for (_, lib) in deps.libraries { 21 | let name = &lib.name; 22 | // Skip dynamic linker/loader and white-listed libs 23 | if name.starts_with("ld-linux") 24 | || name == "ld64.so.2" 25 | || name == "ld64.so.1" 26 | // musl libc, eg: libc.musl-aarch64.so.1 27 | || name.starts_with("ld-musl") 28 | || name.starts_with("libc.") 29 | || policy.lib_whitelist.contains(name) 30 | { 31 | continue; 32 | } 33 | ext_libs.push(lib); 34 | } 35 | Ok(ext_libs) 36 | } 37 | -------------------------------------------------------------------------------- /src/generate_json_schema.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "schemars")] 2 | 3 | use fs_err as fs; 4 | use std::path::PathBuf; 5 | 6 | use anyhow::{bail, Result}; 7 | use pretty_assertions::StrComparison; 8 | use schemars::schema_for; 9 | 10 | use crate::pyproject_toml::ToolMaturin; 11 | 12 | #[derive(Debug, Copy, Clone, PartialEq, Eq, clap::ValueEnum, Default)] 13 | /// The mode to use when generating the JSON schema. 14 | pub enum Mode { 15 | /// Write the JSON schema to the file. 16 | #[default] 17 | Write, 18 | /// Check if the JSON schema is up-to-date. 19 | Check, 20 | /// Print the JSON schema to stdout. 21 | DryRun, 22 | } 23 | 24 | /// Generate the JSON schema for the `pyproject.toml` file. 25 | #[derive(Debug, clap::Parser)] 26 | pub struct GenerateJsonSchemaOptions { 27 | /// The mode to use when generating the JSON schema. 28 | #[arg(long, default_value_t, value_enum)] 29 | pub mode: Mode, 30 | } 31 | 32 | /// Generate the JSON schema for the `pyproject.toml` file. 33 | pub fn generate_json_schema(args: GenerateJsonSchemaOptions) -> Result<()> { 34 | let schema = schema_for!(ToolMaturin); 35 | let schema_string = serde_json::to_string_pretty(&schema).unwrap(); 36 | let filename = "maturin.schema.json"; 37 | let schema_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(filename); 38 | 39 | match args.mode { 40 | Mode::DryRun => { 41 | println!("{schema_string}"); 42 | } 43 | Mode::Check => { 44 | let current = fs::read_to_string(schema_path)?; 45 | if current == schema_string { 46 | println!("Up-to-date: {filename}"); 47 | } else { 48 | let comparison = StrComparison::new(¤t, &schema_string); 49 | bail!("{filename} changed, please run `cargo run --features schemars -- generate-json-schema`:\n{comparison}",); 50 | } 51 | } 52 | Mode::Write => { 53 | let current = fs::read_to_string(&schema_path)?; 54 | if current == schema_string { 55 | println!("Up-to-date: {filename}"); 56 | } else { 57 | println!("Updating: {filename}"); 58 | fs::write(schema_path, schema_string.as_bytes())?; 59 | } 60 | } 61 | } 62 | 63 | Ok(()) 64 | } 65 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Builds wheels from a crate that exposes python bindings through pyo3 2 | //! 3 | //! The high-level api is [BuildOptions], which can be converted into the [BuildContext], which 4 | //! then uses [compile()] and builds the appropriate wheels. 5 | //! 6 | //! # Cargo features 7 | //! 8 | //! Default features: log, upload, rustls 9 | //! 10 | //! - log: Configures pretty-env-logger, even though maturin doesn't use logging itself. 11 | //! 12 | //! - upload: Uses ureq to add the upload command. 13 | //! 14 | //! - rustls: Makes ureq use the rustls stack so that we can build maturin in a CentOS 6 15 | //! docker container and which maturin itself manylinux compliant. 16 | //! 17 | //! - native-tls: Makes ureq use the platform native tls stack 18 | //! 19 | //! - password-storage (off by default): Uses the keyring package to store the password. keyring 20 | //! pulls in a lot of shared libraries and outdated dependencies, so this is off by default, except 21 | //! for the build on the github releases page. 22 | //! (https://github.com/hwchen/secret-service-rs/issues/9) 23 | 24 | #![deny(missing_docs)] 25 | 26 | pub use crate::bridge::{Abi3Version, BridgeModel, PyO3, PyO3Crate}; 27 | pub use crate::build_context::{BuildContext, BuiltWheelMetadata}; 28 | pub use crate::build_options::{BuildOptions, CargoOptions, TargetTriple}; 29 | pub use crate::cargo_toml::CargoToml; 30 | pub use crate::compile::{compile, BuildArtifact}; 31 | pub use crate::develop::{develop, DevelopOptions}; 32 | #[cfg(feature = "schemars")] 33 | pub use crate::generate_json_schema::{generate_json_schema, GenerateJsonSchemaOptions, Mode}; 34 | pub use crate::metadata::{Metadata24, WheelMetadata}; 35 | pub use crate::module_writer::{ 36 | write_dist_info, ModuleWriter, PathWriter, SDistWriter, WheelWriter, 37 | }; 38 | #[cfg(feature = "scaffolding")] 39 | pub use crate::new_project::{init_project, new_project, GenerateProjectOptions}; 40 | pub use crate::pyproject_toml::PyProjectToml; 41 | pub use crate::python_interpreter::PythonInterpreter; 42 | pub use crate::target::Target; 43 | #[cfg(feature = "upload")] 44 | pub use crate::upload::{upload, upload_ui, PublishOpt, Registry, UploadError}; 45 | pub use auditwheel::PlatformTag; 46 | 47 | mod auditwheel; 48 | mod bridge; 49 | mod build_context; 50 | mod build_options; 51 | mod cargo_toml; 52 | #[cfg(feature = "scaffolding")] 53 | /// Generate CI configuration 54 | pub mod ci; 55 | mod compile; 56 | mod cross_compile; 57 | mod develop; 58 | mod generate_json_schema; 59 | mod metadata; 60 | mod module_writer; 61 | #[cfg(feature = "scaffolding")] 62 | mod new_project; 63 | mod project_layout; 64 | pub mod pyproject_toml; 65 | mod python_interpreter; 66 | mod source_distribution; 67 | mod target; 68 | #[cfg(feature = "upload")] 69 | mod upload; 70 | -------------------------------------------------------------------------------- /src/python_interpreter/get_interpreter_metadata.py: -------------------------------------------------------------------------------- 1 | import json 2 | import platform 3 | import sys 4 | import sysconfig 5 | import struct 6 | 7 | if platform.python_implementation() == "PyPy": 8 | # Workaround for PyPy 3.6 on windows: 9 | # - sysconfig.get_config_var("EXT_SUFFIX") differs to importlib until 10 | # Python 3.8 11 | # - PyPy does not load the plain ".pyd" suffix because it expects that's 12 | # for a CPython extension module 13 | # 14 | # This workaround can probably be removed once PyPy for Python 3.8 is the 15 | # main PyPy version. 16 | import importlib.machinery 17 | 18 | ext_suffix = importlib.machinery.EXTENSION_SUFFIXES[0] 19 | else: 20 | ext_suffix = sysconfig.get_config_var("EXT_SUFFIX") 21 | 22 | metadata = { 23 | # sys.implementation.name can differ from platform.python_implementation(), for example 24 | # Pyston has sys.implementation.name == "pyston" while platform.python_implementation() == cpython 25 | "implementation_name": sys.implementation.name, 26 | "executable": sys.executable or None, 27 | "major": sys.version_info.major, 28 | "minor": sys.version_info.minor, 29 | "abiflags": sysconfig.get_config_var("ABIFLAGS"), 30 | "interpreter": platform.python_implementation().lower(), 31 | "ext_suffix": ext_suffix, 32 | "soabi": sysconfig.get_config_var("SOABI") or None, 33 | "platform": sysconfig.get_platform(), 34 | # This one isn't technically necessary, but still very useful for sanity checks 35 | "system": platform.system().lower(), 36 | # This one is for generating a config file for pyo3 37 | "pointer_width": struct.calcsize("P") * 8, 38 | "gil_disabled": sysconfig.get_config_var("Py_GIL_DISABLED") == 1, 39 | } 40 | 41 | print(json.dumps(metadata)) 42 | -------------------------------------------------------------------------------- /src/templates/.gitignore.j2: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | .pytest_cache/ 6 | *.py[cod] 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | .venv/ 14 | env/ 15 | bin/ 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | include/ 26 | man/ 27 | venv/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | pip-selfcheck.json 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | 45 | # Translations 46 | *.mo 47 | 48 | # Mr Developer 49 | .mr.developer.cfg 50 | .project 51 | .pydevproject 52 | 53 | # Rope 54 | .ropeproject 55 | 56 | # Django stuff: 57 | *.log 58 | *.pot 59 | 60 | .DS_Store 61 | 62 | # Sphinx documentation 63 | docs/_build/ 64 | 65 | # PyCharm 66 | .idea/ 67 | 68 | # VSCode 69 | .vscode/ 70 | 71 | # Pyenv 72 | .python-version 73 | -------------------------------------------------------------------------------- /src/templates/Cargo.toml.j2: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "{{ name }}" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | {%- if bindings != "bin" %} 8 | [lib] 9 | name = "{{ crate_name }}" 10 | crate-type = ["cdylib"] 11 | {%- endif %} 12 | 13 | [dependencies] 14 | {% if bindings == "pyo3" -%} 15 | pyo3 = "0.24.0" 16 | {% elif bindings == "uniffi" -%} 17 | uniffi = "0.28.0" 18 | 19 | [build-dependencies] 20 | uniffi = { version = "0.28.0", features = ["build"] } 21 | {% endif -%} 22 | -------------------------------------------------------------------------------- /src/templates/__init__.py.j2: -------------------------------------------------------------------------------- 1 | from .{{ crate_name }} import * 2 | 3 | 4 | __doc__ = {{ crate_name }}.__doc__ 5 | if hasattr({{ crate_name }}, "__all__"): 6 | __all__ = {{ crate_name }}.__all__ 7 | -------------------------------------------------------------------------------- /src/templates/build.rs.j2: -------------------------------------------------------------------------------- 1 | {%- if bindings == "uniffi" -%} 2 | fn main() { 3 | uniffi::generate_scaffolding("./src/example.udl").unwrap(); 4 | } 5 | {% endif -%} 6 | -------------------------------------------------------------------------------- /src/templates/example.udl.j2: -------------------------------------------------------------------------------- 1 | namespace example { 2 | u32 add(u32 a, u32 b); 3 | }; 4 | -------------------------------------------------------------------------------- /src/templates/lib.rs.j2: -------------------------------------------------------------------------------- 1 | {%- if bindings == "pyo3" -%} 2 | use pyo3::prelude::*; 3 | 4 | /// Formats the sum of two numbers as string. 5 | #[pyfunction] 6 | fn sum_as_string(a: usize, b: usize) -> PyResult { 7 | Ok((a + b).to_string()) 8 | } 9 | 10 | /// A Python module implemented in Rust. 11 | #[pymodule] 12 | fn {{crate_name}}(m: &Bound<'_, PyModule>) -> PyResult<()> { 13 | m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; 14 | Ok(()) 15 | } 16 | {%- elif bindings == "uniffi" -%} 17 | fn add(a: u32, b: u32) -> u32 { 18 | a + b 19 | } 20 | 21 | uniffi::include_scaffolding!("example"); 22 | {%- endif %} 23 | -------------------------------------------------------------------------------- /src/templates/main.rs.j2: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /src/templates/pyproject.toml.j2: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>={{ version_major }}.{{ version_minor }},<{{ version_major + 1 }}.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "{{ name }}" 7 | requires-python = ">=3.8" 8 | classifiers = [ 9 | "Programming Language :: Rust", 10 | "Programming Language :: Python :: Implementation :: CPython", 11 | "Programming Language :: Python :: Implementation :: PyPy", 12 | ] 13 | {% if bindings == "cffi" -%} 14 | dependencies = ["cffi"] 15 | {% endif -%} 16 | dynamic = ["version"] 17 | {% if mixed_non_src -%} 18 | [project.optional-dependencies] 19 | tests = [ 20 | "pytest", 21 | ] 22 | {% endif -%} 23 | 24 | {% if bindings in ["bin", "cffi", "pyo3"] or mixed_non_src -%} 25 | [tool.maturin] 26 | {% if bindings == "cffi" or bindings == "bin" -%} 27 | bindings = "{{ bindings }}" 28 | {% endif -%} 29 | {% if mixed_non_src -%} 30 | python-source = "python" 31 | {% endif -%} 32 | {% if bindings == "pyo3" -%} 33 | features = ["pyo3/extension-module"] 34 | {% endif -%} 35 | {% endif -%} 36 | -------------------------------------------------------------------------------- /src/templates/test_all.py.j2: -------------------------------------------------------------------------------- 1 | import pytest 2 | import {{ crate_name }} 3 | 4 | 5 | def test_sum_as_string(): 6 | assert {{ crate_name }}.sum_as_string(1, 1) == "2" 7 | -------------------------------------------------------------------------------- /sysconfig/Readme.md: -------------------------------------------------------------------------------- 1 | This folder contains all the sysconfigs (`python -m sysconfig`) I came across. I collected those because they differ highly across versions and operating systems, but are essential for naming wheels and libraries. 2 | -------------------------------------------------------------------------------- /sysconfig/cpython-win-3.7.txt: -------------------------------------------------------------------------------- 1 | Platform: "win-amd64" 2 | Python version: "3.7" 3 | Current installation scheme: "nt" 4 | 5 | Paths: 6 | data = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 7 | include = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Include" 8 | platinclude = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Include" 9 | platlib = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Lib\site-packages" 10 | platstdlib = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Lib" 11 | purelib = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Lib\site-packages" 12 | scripts = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Scripts" 13 | stdlib = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Lib" 14 | 15 | Variables: 16 | BINDIR = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 17 | BINLIBDEST = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Lib" 18 | EXE = ".exe" 19 | EXT_SUFFIX = ".pyd" 20 | INCLUDEPY = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Include" 21 | LIBDEST = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37\Lib" 22 | SO = ".pyd" 23 | VERSION = "37" 24 | abiflags = "" 25 | base = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 26 | exec_prefix = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 27 | installed_base = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 28 | installed_platbase = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 29 | platbase = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 30 | prefix = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 31 | projectbase = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 32 | py_version = "3.7.0" 33 | py_version_nodot = "37" 34 | py_version_short = "3.7" 35 | srcdir = "C:\Users\Konstantin\AppData\Local\Programs\Python\Python37" 36 | userbase = "C:\Users\Konstantin\AppData\Roaming\Python" 37 | -------------------------------------------------------------------------------- /sysconfig/cpython-win-3.9-aarch64.txt: -------------------------------------------------------------------------------- 1 | Platform: "win-arm64" 2 | Python version: "3.9" 3 | Current installation scheme: "nt" 4 | 5 | Paths: 6 | data = "C:\Program Files (Arm)\Python-3.9.1" 7 | include = "C:\Program Files (Arm)\Python-3.9.1\Include" 8 | platinclude = "C:\Program Files (Arm)\Python-3.9.1\Include" 9 | platlib = "C:\Program Files (Arm)\Python-3.9.1\Lib\site-packages" 10 | platstdlib = "C:\Program Files (Arm)\Python-3.9.1\Lib" 11 | purelib = "C:\Program Files (Arm)\Python-3.9.1\Lib\site-packages" 12 | scripts = "C:\Program Files (Arm)\Python-3.9.1\Scripts" 13 | stdlib = "C:\Program Files (Arm)\Python-3.9.1\Lib" 14 | 15 | Variables: 16 | BINDIR = "C:\Program Files (Arm)\Python-3.9.1" 17 | BINLIBDEST = "C:\Program Files (Arm)\Python-3.9.1\Lib" 18 | EXE = ".exe" 19 | EXT_SUFFIX = ".pyd" 20 | INCLUDEPY = "C:\Program Files (Arm)\Python-3.9.1\Include" 21 | LIBDEST = "C:\Program Files (Arm)\Python-3.9.1\Lib" 22 | SO = ".pyd" 23 | TZPATH = "" 24 | VERSION = "39" 25 | abiflags = "" 26 | base = "C:\Program Files (Arm)\Python-3.9.1" 27 | exec_prefix = "C:\Program Files (Arm)\Python-3.9.1" 28 | installed_base = "C:\Program Files (Arm)\Python-3.9.1" 29 | installed_platbase = "C:\Program Files (Arm)\Python-3.9.1" 30 | platbase = "C:\Program Files (Arm)\Python-3.9.1" 31 | platlibdir = "lib" 32 | prefix = "C:\Program Files (Arm)\Python-3.9.1" 33 | projectbase = "C:\Program Files (Arm)\Python-3.9.1" 34 | py_version = "3.9.1" 35 | py_version_nodot = "39" 36 | py_version_short = "3.9" 37 | srcdir = "C:\Program Files (Arm)\Python-3.9.1" 38 | userbase = "C:\Users\messense\AppData\Roaming\Python" 39 | -------------------------------------------------------------------------------- /sysconfig/pypy-linux-3.7-7.3.txt: -------------------------------------------------------------------------------- 1 | Platform: "linux-x86_64" 2 | Python version: "3.7" 3 | Current installation scheme: "pypy" 4 | 5 | Paths: 6 | data = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3" 7 | include = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/include" 8 | platinclude = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/include" 9 | platlib = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/site-packages" 10 | platstdlib = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/lib-pypy" 11 | purelib = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/site-packages" 12 | scripts = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/bin" 13 | stdlib = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/lib-pypy" 14 | 15 | Variables: 16 | AR = "ar" 17 | ARFLAGS = "rc" 18 | CC = "gcc -pthread" 19 | CCSHARED = "-fPIC" 20 | CFLAGS = "-DNDEBUG -O2" 21 | CXX = "g++ -pthread" 22 | EXE = "" 23 | EXT_SUFFIX = ".pypy37-pp73-x86_64-linux-gnu.so" 24 | GNULD = "yes" 25 | INCLUDEPY = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/include" 26 | LDSHARED = "gcc -pthread -shared" 27 | LIBDIR = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/bin" 28 | LIBRARY = "" 29 | OPT = "-DNDEBUG -O2" 30 | SHLIB_SUFFIX = ".so" 31 | SO = ".pypy37-pp73-x86_64-linux-gnu.so" 32 | SOABI = "pypy37-pp73" 33 | abiflags = "" 34 | base = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3" 35 | exec_prefix = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3" 36 | implementation = "PyPy" 37 | implementation_lower = "pypy" 38 | installed_base = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3" 39 | installed_platbase = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3" 40 | platbase = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3" 41 | prefix = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3" 42 | projectbase = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/bin" 43 | py_version = "3.7.9" 44 | py_version_nodot = "37" 45 | py_version_short = "3.7" 46 | srcdir = "/home/konsti/.pyenv/versions/pypy3.7-7.3.3/lib-pypy/config-3.7" 47 | userbase = "/home/konsti/.local" 48 | User: 49 | data = "/home/konsti/.local" 50 | include = "/home/konsti/.local/include/pypy3.7" 51 | platlib = "/home/konsti/.local/lib/pypy3.7/site-packages" 52 | platstdlib = "/home/konsti/.local/lib/pypy3.7" 53 | purelib = "/home/konsti/.local/lib/pypy3.7/site-packages" 54 | scripts = "/home/konsti/.local/bin" 55 | stdlib = "/home/konsti/.local/lib/pypy3.7" 56 | -------------------------------------------------------------------------------- /sysconfig/pypy-linux-ppc64le-3.7-7.3.txt: -------------------------------------------------------------------------------- 1 | Platform: "linux-ppc64le" 2 | Python version: "3.7" 3 | Current installation scheme: "pypy" 4 | 5 | Paths: 6 | data = "/usr/lib64/pypy3.7" 7 | include = "/usr/lib64/pypy3.7/include" 8 | platinclude = "/usr/lib64/pypy3.7/include" 9 | platlib = "/usr/lib64/pypy3.7/site-packages" 10 | platstdlib = "/usr/lib64/pypy3.7/lib_pypy" 11 | purelib = "/usr/lib64/pypy3.7/site-packages" 12 | scripts = "/usr/lib64/pypy3.7/bin" 13 | stdlib = "/usr/lib64/pypy3.7/lib_pypy" 14 | 15 | Variables: 16 | ABIFLAGS = "" 17 | AR = "ar" 18 | ARFLAGS = "rc" 19 | CC = "cc -pthread" 20 | CCSHARED = "-fPIC" 21 | CFLAGS = "-DNDEBUG -O2" 22 | CXX = "c++ -pthread" 23 | EXE = "" 24 | EXT_SUFFIX = ".pypy37-pp73-ppc_64-linux-gnu.so" 25 | INCLUDEPY = "/usr/lib64/pypy3.7/include" 26 | LDLIBRARY = "libpypy3-c.so" 27 | LDSHARED = "cc -pthread -shared" 28 | LDVERSION = "3.7" 29 | LIBDIR = "/usr/lib64/pypy3.7/bin" 30 | LIBRARY = "" 31 | MULTIARCH = "ppc_64-linux-gnu" 32 | OPT = "-DNDEBUG -O2" 33 | Py_DEBUG = "0" 34 | Py_ENABLE_SHARED = "0" 35 | SHLIB_SUFFIX = ".so" 36 | SIZEOF_VOID_P = "8" 37 | SO = ".pypy37-pp73-ppc_64-linux-gnu.so" 38 | SOABI = "pypy37-pp73" 39 | VERSION = "3.7" 40 | abiflags = "" 41 | base = "/usr/lib64/pypy3.7" 42 | exec_prefix = "/usr/lib64/pypy3.7" 43 | implementation = "PyPy" 44 | implementation_lower = "pypy" 45 | installed_base = "/usr/lib64/pypy3.7" 46 | installed_platbase = "/usr/lib64/pypy3.7" 47 | platbase = "/usr/lib64/pypy3.7" 48 | prefix = "/usr/lib64/pypy3.7" 49 | projectbase = "/usr/lib64/pypy3.7/bin" 50 | py_version = "3.7.13" 51 | py_version_nodot = "37" 52 | py_version_short = "3.7" 53 | srcdir = "/usr/lib64/pypy3.7/lib_pypy/config-3.7-ppc_64-linux-gnu" 54 | userbase = "/root/.local" 55 | User: 56 | data = "/root/.local" 57 | include = "/root/.local/include/pypy3.7" 58 | platlib = "/root/.local/lib/pypy3.7/site-packages" 59 | platstdlib = "/root/.local/lib/pypy3.7" 60 | purelib = "/root/.local/lib/pypy3.7/site-packages" 61 | scripts = "/root/.local/bin" 62 | stdlib = "/root/.local/lib/pypy3.7" 63 | -------------------------------------------------------------------------------- /sysconfig/pypy-linux-ppc64le-3.8-7.3.txt: -------------------------------------------------------------------------------- 1 | Platform: "linux-ppc64le" 2 | Python version: "3.8" 3 | Current installation scheme: "posix_prefix" 4 | 5 | Paths: 6 | data = "/usr/lib64/pypy3.8" 7 | include = "/usr/lib64/pypy3.8/include/pypy3.8" 8 | platinclude = "/usr/lib64/pypy3.8/include/pypy3.8" 9 | platlib = "/usr/lib64/pypy3.8/lib/pypy3.8/site-packages" 10 | platstdlib = "/usr/lib64/pypy3.8/lib/pypy3.8" 11 | purelib = "/usr/lib64/pypy3.8/lib/pypy3.8/site-packages" 12 | scripts = "/usr/lib64/pypy3.8/bin" 13 | stdlib = "/usr/lib64/pypy3.8/lib/pypy3.8" 14 | 15 | Variables: 16 | ABIFLAGS = "" 17 | AR = "ar" 18 | ARFLAGS = "rc" 19 | CC = "cc -pthread" 20 | CCSHARED = "-fPIC" 21 | CFLAGS = "-DNDEBUG -O2" 22 | CXX = "c++ -pthread" 23 | EXE = "" 24 | EXT_SUFFIX = ".pypy38-pp73-ppc_64-linux-gnu.so" 25 | INCLUDEPY = "/usr/lib64/pypy3.8/include/pypy3.8" 26 | LDFLAGS = "-Wl,-Bsymbolic-functions" 27 | LDLIBRARY = "libpypy3-c.so" 28 | LDSHARED = "cc -pthread -shared -Wl,-Bsymbolic-functions" 29 | LDVERSION = "3.8" 30 | LIBDIR = "/usr/lib64/pypy3.8/bin" 31 | LIBRARY = "" 32 | MULTIARCH = "ppc_64-linux-gnu" 33 | OPT = "-DNDEBUG -O2" 34 | Py_DEBUG = "0" 35 | Py_ENABLE_SHARED = "0" 36 | SHLIB_SUFFIX = ".so" 37 | SIZEOF_VOID_P = "8" 38 | SO = ".pypy38-pp73-ppc_64-linux-gnu.so" 39 | SOABI = "pypy38-pp73" 40 | VERSION = "3.8" 41 | abiflags = "" 42 | base = "/usr/lib64/pypy3.8" 43 | exec_prefix = "/usr/lib64/pypy3.8" 44 | implementation = "PyPy" 45 | implementation_lower = "pypy" 46 | installed_base = "/usr/lib64/pypy3.8" 47 | installed_platbase = "/usr/lib64/pypy3.8" 48 | platbase = "/usr/lib64/pypy3.8" 49 | prefix = "/usr/lib64/pypy3.8" 50 | projectbase = "/usr/lib64/pypy3.8/bin" 51 | py_version = "3.8.13" 52 | py_version_nodot = "38" 53 | py_version_short = "3.8" 54 | srcdir = "/usr/lib64/pypy3.8/bin" 55 | userbase = "/root/.local" 56 | User: 57 | data = "/root/.local" 58 | include = "/root/.local/include/pypy3.8" 59 | platlib = "/root/.local/lib/pypy3.8/site-packages" 60 | platstdlib = "/root/.local/lib/pypy3.8" 61 | purelib = "/root/.local/lib/pypy3.8/site-packages" 62 | scripts = "/root/.local/bin" 63 | stdlib = "/root/.local/lib/pypy3.8" 64 | -------------------------------------------------------------------------------- /sysconfig/pypy-linux-ppc64le-3.9-7.3.txt: -------------------------------------------------------------------------------- 1 | Platform: "linux-ppc64le" 2 | Python version: "3.9" 3 | Current installation scheme: "posix_prefix" 4 | 5 | Paths: 6 | data = "/usr" 7 | include = "/usr/include/pypy3.9" 8 | platinclude = "/usr/include/pypy3.9" 9 | platlib = "/usr/lib64/pypy3.9/site-packages" 10 | platstdlib = "/usr/lib64/pypy3.9" 11 | purelib = "/usr/lib/pypy3.9/site-packages" 12 | scripts = "/usr/bin" 13 | stdlib = "/usr/lib64/pypy3.9" 14 | 15 | Variables: 16 | ABIFLAGS = "" 17 | AR = "ar" 18 | ARFLAGS = "rc" 19 | CC = "cc -pthread" 20 | CCSHARED = "-fPIC" 21 | CFLAGS = "-DNDEBUG -O2" 22 | CXX = "c++ -pthread" 23 | EXE = "" 24 | EXT_SUFFIX = ".pypy39-pp73-ppc_64-linux-gnu.so" 25 | INCLUDEPY = "/usr/include/pypy3.9" 26 | LDFLAGS = "-Wl,-Bsymbolic-functions" 27 | LDLIBRARY = "libpypy3.9-c.so" 28 | LDSHARED = "cc -pthread -shared -Wl,-Bsymbolic-functions" 29 | LDVERSION = "3.9" 30 | LIBDIR = "/usr/bin" 31 | LIBRARY = "" 32 | MULTIARCH = "ppc_64-linux-gnu" 33 | OPT = "-DNDEBUG -O2" 34 | Py_DEBUG = "0" 35 | Py_ENABLE_SHARED = "0" 36 | SHLIB_SUFFIX = ".so" 37 | SIZEOF_VOID_P = "8" 38 | SO = ".pypy39-pp73-ppc_64-linux-gnu.so" 39 | SOABI = "pypy39-pp73" 40 | TZPATH = "/usr/share/zoneinfo:/usr/lib/zoneinfo:/usr/share/lib/zoneinfo:/usr/../etc/zoneinfo" 41 | VERSION = "3.9" 42 | abiflags = "" 43 | base = "/usr" 44 | exec_prefix = "/usr" 45 | implementation = "PyPy" 46 | implementation_lower = "pypy" 47 | installed_base = "/usr" 48 | installed_platbase = "/usr" 49 | platbase = "/usr" 50 | platlibdir = "lib64" 51 | prefix = "/usr" 52 | projectbase = "/usr/bin" 53 | py_version = "3.9.12" 54 | py_version_nodot = "39" 55 | py_version_short = "3.9" 56 | srcdir = "/usr/bin" 57 | userbase = "/root/.local" 58 | User: 59 | data = "/root/.local" 60 | include = "/root/.local/include/pypy3.9" 61 | platlib = "/root/.local/lib64/pypy3.9/site-packages" 62 | platstdlib = "/root/.local/lib64/pypy3.9" 63 | purelib = "/root/.local/lib/pypy3.9/site-packages" 64 | scripts = "/root/.local/bin" 65 | stdlib = "/root/.local/lib64/pypy3.9" 66 | -------------------------------------------------------------------------------- /sysconfig/pypy-linux-s390x-3.7-7.3.txt: -------------------------------------------------------------------------------- 1 | Platform: "linux-s390x" 2 | Python version: "3.7" 3 | Current installation scheme: "pypy" 4 | 5 | Paths: 6 | data = "/usr/lib64/pypy3.7" 7 | include = "/usr/lib64/pypy3.7/include" 8 | platinclude = "/usr/lib64/pypy3.7/include" 9 | platlib = "/usr/lib64/pypy3.7/site-packages" 10 | platstdlib = "/usr/lib64/pypy3.7/lib_pypy" 11 | purelib = "/usr/lib64/pypy3.7/site-packages" 12 | scripts = "/usr/lib64/pypy3.7/bin" 13 | stdlib = "/usr/lib64/pypy3.7/lib_pypy" 14 | 15 | Variables: 16 | ABIFLAGS = "" 17 | AR = "ar" 18 | ARFLAGS = "rc" 19 | CC = "cc -pthread" 20 | CCSHARED = "-fPIC" 21 | CFLAGS = "-DNDEBUG -O2" 22 | CXX = "c++ -pthread" 23 | EXE = "" 24 | EXT_SUFFIX = ".pypy37-pp73-s390x-linux-gnu.so" 25 | INCLUDEPY = "/usr/lib64/pypy3.7/include" 26 | LDLIBRARY = "libpypy3-c.so" 27 | LDSHARED = "cc -pthread -shared" 28 | LDVERSION = "3.7" 29 | LIBDIR = "/usr/lib64/pypy3.7/bin" 30 | LIBRARY = "" 31 | MULTIARCH = "s390x-linux-gnu" 32 | OPT = "-DNDEBUG -O2" 33 | Py_DEBUG = "0" 34 | Py_ENABLE_SHARED = "0" 35 | SHLIB_SUFFIX = ".so" 36 | SIZEOF_VOID_P = "8" 37 | SO = ".pypy37-pp73-s390x-linux-gnu.so" 38 | SOABI = "pypy37-pp73" 39 | VERSION = "3.7" 40 | abiflags = "" 41 | base = "/usr/lib64/pypy3.7" 42 | exec_prefix = "/usr/lib64/pypy3.7" 43 | implementation = "PyPy" 44 | implementation_lower = "pypy" 45 | installed_base = "/usr/lib64/pypy3.7" 46 | installed_platbase = "/usr/lib64/pypy3.7" 47 | platbase = "/usr/lib64/pypy3.7" 48 | prefix = "/usr/lib64/pypy3.7" 49 | projectbase = "/usr/lib64/pypy3.7/bin" 50 | py_version = "3.7.13" 51 | py_version_nodot = "37" 52 | py_version_short = "3.7" 53 | srcdir = "/usr/lib64/pypy3.7/lib_pypy/config-3.7-s390x-linux-gnu" 54 | userbase = "/root/.local" 55 | User: 56 | data = "/root/.local" 57 | include = "/root/.local/include/pypy3.7" 58 | platlib = "/root/.local/lib/pypy3.7/site-packages" 59 | platstdlib = "/root/.local/lib/pypy3.7" 60 | purelib = "/root/.local/lib/pypy3.7/site-packages" 61 | scripts = "/root/.local/bin" 62 | stdlib = "/root/.local/lib/pypy3.7" 63 | -------------------------------------------------------------------------------- /sysconfig/pypy-linux-s390x-3.8-7.3.txt: -------------------------------------------------------------------------------- 1 | Platform: "linux-s390x" 2 | Python version: "3.8" 3 | Current installation scheme: "posix_prefix" 4 | 5 | Paths: 6 | data = "/usr/lib64/pypy3.8" 7 | include = "/usr/lib64/pypy3.8/include/pypy3.8" 8 | platinclude = "/usr/lib64/pypy3.8/include/pypy3.8" 9 | platlib = "/usr/lib64/pypy3.8/lib/pypy3.8/site-packages" 10 | platstdlib = "/usr/lib64/pypy3.8/lib/pypy3.8" 11 | purelib = "/usr/lib64/pypy3.8/lib/pypy3.8/site-packages" 12 | scripts = "/usr/lib64/pypy3.8/bin" 13 | stdlib = "/usr/lib64/pypy3.8/lib/pypy3.8" 14 | 15 | Variables: 16 | ABIFLAGS = "" 17 | AR = "ar" 18 | ARFLAGS = "rc" 19 | CC = "cc -pthread" 20 | CCSHARED = "-fPIC" 21 | CFLAGS = "-DNDEBUG -O2" 22 | CXX = "c++ -pthread" 23 | EXE = "" 24 | EXT_SUFFIX = ".pypy38-pp73-s390x-linux-gnu.so" 25 | INCLUDEPY = "/usr/lib64/pypy3.8/include/pypy3.8" 26 | LDFLAGS = "-Wl,-Bsymbolic-functions" 27 | LDLIBRARY = "libpypy3-c.so" 28 | LDSHARED = "cc -pthread -shared -Wl,-Bsymbolic-functions" 29 | LDVERSION = "3.8" 30 | LIBDIR = "/usr/lib64/pypy3.8/bin" 31 | LIBRARY = "" 32 | MULTIARCH = "s390x-linux-gnu" 33 | OPT = "-DNDEBUG -O2" 34 | Py_DEBUG = "0" 35 | Py_ENABLE_SHARED = "0" 36 | SHLIB_SUFFIX = ".so" 37 | SIZEOF_VOID_P = "8" 38 | SO = ".pypy38-pp73-s390x-linux-gnu.so" 39 | SOABI = "pypy38-pp73" 40 | VERSION = "3.8" 41 | abiflags = "" 42 | base = "/usr/lib64/pypy3.8" 43 | exec_prefix = "/usr/lib64/pypy3.8" 44 | implementation = "PyPy" 45 | implementation_lower = "pypy" 46 | installed_base = "/usr/lib64/pypy3.8" 47 | installed_platbase = "/usr/lib64/pypy3.8" 48 | platbase = "/usr/lib64/pypy3.8" 49 | prefix = "/usr/lib64/pypy3.8" 50 | projectbase = "/usr/lib64/pypy3.8/bin" 51 | py_version = "3.8.13" 52 | py_version_nodot = "38" 53 | py_version_short = "3.8" 54 | srcdir = "/usr/lib64/pypy3.8/bin" 55 | userbase = "/root/.local" 56 | User: 57 | data = "/root/.local" 58 | include = "/root/.local/include/pypy3.8" 59 | platlib = "/root/.local/lib/pypy3.8/site-packages" 60 | platstdlib = "/root/.local/lib/pypy3.8" 61 | purelib = "/root/.local/lib/pypy3.8/site-packages" 62 | scripts = "/root/.local/bin" 63 | stdlib = "/root/.local/lib/pypy3.8" 64 | -------------------------------------------------------------------------------- /sysconfig/pypy-linux-s390x-3.9-7.3.txt: -------------------------------------------------------------------------------- 1 | Platform: "linux-s390" 2 | Python version: "3.9" 3 | Current installation scheme: "posix_prefix" 4 | 5 | Paths: 6 | data = "/usr" 7 | include = "/usr/include/pypy3.9" 8 | platinclude = "/usr/include/pypy3.9" 9 | platlib = "/usr/lib64/pypy3.9/site-packages" 10 | platstdlib = "/usr/lib64/pypy3.9" 11 | purelib = "/usr/lib/pypy3.9/site-packages" 12 | scripts = "/usr/bin" 13 | stdlib = "/usr/lib64/pypy3.9" 14 | 15 | Variables: 16 | ABIFLAGS = "" 17 | AR = "ar" 18 | ARFLAGS = "rc" 19 | CC = "cc -pthread" 20 | CCSHARED = "-fPIC" 21 | CFLAGS = "-DNDEBUG -O2" 22 | CXX = "c++ -pthread" 23 | EXE = "" 24 | EXT_SUFFIX = ".pypy39-pp73-s390x-linux-gnu.so" 25 | INCLUDEPY = "/usr/include/pypy3.9" 26 | LDFLAGS = "-Wl,-Bsymbolic-functions" 27 | LDLIBRARY = "libpypy3.9-c.so" 28 | LDSHARED = "cc -pthread -shared -Wl,-Bsymbolic-functions" 29 | LDVERSION = "3.9" 30 | LIBDIR = "/usr/bin" 31 | LIBRARY = "" 32 | MULTIARCH = "s390x-linux-gnu" 33 | OPT = "-DNDEBUG -O2" 34 | Py_DEBUG = "0" 35 | Py_ENABLE_SHARED = "0" 36 | SHLIB_SUFFIX = ".so" 37 | SIZEOF_VOID_P = "8" 38 | SO = ".pypy39-pp73-s390x-linux-gnu.so" 39 | SOABI = "pypy39-pp73" 40 | TZPATH = "/usr/share/zoneinfo:/usr/lib/zoneinfo:/usr/share/lib/zoneinfo:/usr/../etc/zoneinfo" 41 | VERSION = "3.9" 42 | abiflags = "" 43 | base = "/usr" 44 | exec_prefix = "/usr" 45 | implementation = "PyPy" 46 | implementation_lower = "pypy" 47 | installed_base = "/usr" 48 | installed_platbase = "/usr" 49 | platbase = "/usr" 50 | platlibdir = "lib64" 51 | prefix = "/usr" 52 | projectbase = "/usr/bin" 53 | py_version = "3.9.12" 54 | py_version_nodot = "39" 55 | py_version_short = "3.9" 56 | srcdir = "/usr/bin" 57 | userbase = "/root/.local" 58 | User: 59 | data = "/root/.local" 60 | include = "/root/.local/include/pypy3.9" 61 | platlib = "/root/.local/lib64/pypy3.9/site-packages" 62 | platstdlib = "/root/.local/lib64/pypy3.9" 63 | purelib = "/root/.local/lib/pypy3.9/site-packages" 64 | scripts = "/root/.local/bin" 65 | stdlib = "/root/.local/lib64/pypy3.9" 66 | -------------------------------------------------------------------------------- /sysconfig/pypy-macos-3.7-7.3.txt: -------------------------------------------------------------------------------- 1 | Platform: "macosx-10.7-x86_64" 2 | Python version: "3.7" 3 | Current installation scheme: "pypy" 4 | 5 | Paths: 6 | data = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5" 7 | include = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/include" 8 | platinclude = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/include" 9 | platlib = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/site-packages" 10 | platstdlib = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/lib-pypy" 11 | purelib = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/site-packages" 12 | scripts = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/bin" 13 | stdlib = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/lib-pypy" 14 | 15 | Variables: 16 | AR = "ar" 17 | ARFLAGS = "rc" 18 | CC = "gcc -pthread -arch x86_64" 19 | CCSHARED = "-fPIC" 20 | CFLAGS = "-DNDEBUG -O2" 21 | CXX = "g++ -pthread -arch x86_64" 22 | EXE = "" 23 | EXT_SUFFIX = ".pypy37-pp73-darwin.so" 24 | GNULD = "yes" 25 | INCLUDEPY = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/include" 26 | LDLIBRARY = "libpypy3-c.so" 27 | LDSHARED = "gcc -pthread -arch x86_64 -shared -undefined dynamic_lookup" 28 | LIBDIR = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/bin" 29 | LIBRARY = "" 30 | MACOSX_DEPLOYMENT_TARGET = "10.7" 31 | OPT = "-DNDEBUG -O2" 32 | SHLIB_SUFFIX = ".so" 33 | SO = ".pypy37-pp73-darwin.so" 34 | SOABI = "pypy37-pp73" 35 | abiflags = "" 36 | base = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5" 37 | exec_prefix = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5" 38 | implementation = "PyPy" 39 | implementation_lower = "pypy" 40 | installed_base = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5" 41 | installed_platbase = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5" 42 | platbase = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5" 43 | prefix = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5" 44 | projectbase = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/bin" 45 | py_version = "3.7.10" 46 | py_version_nodot = "37" 47 | py_version_short = "3.7" 48 | srcdir = "/Users/messense/.pyenv/versions/pypy3.7-7.3.5/lib-pypy/config-3.7" 49 | userbase = "/Users/messense/.local" 50 | User: 51 | data = "/Users/messense/.local" 52 | include = "/Users/messense/.local/include/pypy3.7" 53 | platlib = "/Users/messense/.local/lib/pypy3.7/site-packages" 54 | platstdlib = "/Users/messense/.local/lib/pypy3.7" 55 | purelib = "/Users/messense/.local/lib/pypy3.7/site-packages" 56 | scripts = "/Users/messense/.local/bin" 57 | stdlib = "/Users/messense/.local/lib/pypy3.7" -------------------------------------------------------------------------------- /test-crates/cargo-mock/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo-mock" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | 7 | [[bin]] 8 | name = "cargo" 9 | path = "src/main.rs" 10 | 11 | [dependencies] 12 | anyhow = "1.0.38" 13 | cargo_metadata = "0.18.1" 14 | serde_json = "1.0.62" 15 | -------------------------------------------------------------------------------- /test-crates/cargo-update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | for d in ./*; do 3 | if [ -d "$d" ]; then 4 | if [ -f "$d/Cargo.lock" ]; then 5 | cargo update --manifest-path "$d/Cargo.toml" 6 | echo "$d updated" 7 | fi 8 | fi 9 | done 10 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/.gitignore: -------------------------------------------------------------------------------- 1 | cffi_mixed/cffi_mixed 2 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "cffi-mixed" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cffi-mixed" 3 | version = "0.1.0" 4 | authors = ["Armin Ronacher "] 5 | edition = "2021" 6 | 7 | [lib] 8 | name = "cffi_mixed" 9 | crate-type = ["cdylib"] 10 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/Readme.md: -------------------------------------------------------------------------------- 1 | # cffi-mixed 2 | 3 | A package for testing maturin with a cffi wrapper with a rust backend and a python wrapper. 4 | 5 | Read the [cffi guide](https://cffi.readthedocs.io/en/latest/index.html) to learn how to use the generated `ffi` and `lib` objects. 6 | 7 | The package contains a `Point` type implemented in rust and a `Line` class consisting of two points implemented in python 8 | 9 | ## Usage 10 | 11 | ```bash 12 | pip install . 13 | ``` 14 | 15 | ```python 16 | import cffi_mixed 17 | 18 | from cffi_mixed import Line 19 | 20 | point = cffi_mixed.lib.get_origin() 21 | point.x = 10 22 | point.y = 10 23 | assert cffi_mixed.lib.is_in_range(point, 15) 24 | 25 | assert Line(2, 5, 6, 8).length() == 5 26 | ``` 27 | 28 | ## Testing 29 | 30 | Install tox: 31 | 32 | ```bash 33 | pip install tox 34 | ``` 35 | 36 | Run it: 37 | 38 | ```bash 39 | tox 40 | ``` 41 | 42 | The tests are in `test_cffi_mixed.py`, while the configuration is in tox.ini 43 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/cffi_mixed/__init__.py: -------------------------------------------------------------------------------- 1 | from .cffi_mixed import ffi, lib 2 | from .line import Line 3 | 4 | __all__ = ["ffi", "lib", "Line"] 5 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/cffi_mixed/line.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | from .cffi_mixed import ffi 4 | 5 | 6 | class Line: 7 | def __init__(self, x1: float, y1: float, x2: float, y2: float): 8 | # You can pass a tuple/list or a dict as value for a public rust struct 9 | self.start = ffi.new("Point *", {"x": x1, "y": y1}) 10 | self.end = ffi.new("Point *", (x2, y2)) 11 | 12 | def length(self) -> float: 13 | """Returns the length of the line.""" 14 | return math.sqrt((self.end.x - self.start.x) ** 2 + (self.end.y - self.start.y) ** 2) 15 | 16 | def __str__(self) -> str: 17 | return "Line from ({},{}) to ({},{})".format(self.start.x, self.start.y, self.end.x, self.end.y) 18 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import cffi_mixed 4 | 5 | from cffi_mixed import Line 6 | 7 | point = cffi_mixed.lib.get_origin() 8 | point.x = 10 9 | point.y = 10 10 | assert cffi_mixed.lib.is_in_range(point, 15) 11 | 12 | assert Line(2, 5, 6, 8).length() == 5 13 | 14 | print("SUCCESS") 15 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "cffi-mixed" 7 | dependencies = ["cffi"] 8 | dynamic = ["version"] 9 | 10 | [tool.maturin] 11 | bindings = "cffi" 12 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/requirements_test.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | cffi 3 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | pub struct Point { 3 | pub x: f32, 4 | pub y: f32, 5 | } 6 | 7 | #[repr(u32)] 8 | pub enum Foo { 9 | A = 1, 10 | B, 11 | C, 12 | } 13 | 14 | #[no_mangle] 15 | pub unsafe extern "C" fn get_origin() -> Point { 16 | Point { x: 0.0, y: 0.0 } 17 | } 18 | 19 | #[no_mangle] 20 | pub unsafe extern "C" fn add_points(p1: Point, p2: Point) -> Point { 21 | Point { 22 | x: p1.x + p2.x, 23 | y: p1.y + p2.y, 24 | } 25 | } 26 | 27 | #[no_mangle] 28 | pub unsafe extern "C" fn is_in_range(point: Point, range: f32) -> bool { 29 | (point.x.powi(2) + point.y.powi(2)).sqrt() <= range 30 | } 31 | 32 | #[no_mangle] 33 | pub unsafe extern "C" fn print_foo(foo: *const Foo) { 34 | println!( 35 | "{}", 36 | match *foo { 37 | Foo::A => "a", 38 | Foo::B => "b", 39 | Foo::C => "c", 40 | } 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/test_cffi_mixed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import cffi_mixed 4 | 5 | from cffi_mixed import Line 6 | 7 | 8 | def test_in_range(): 9 | point = cffi_mixed.lib.get_origin() 10 | point.x = 10 11 | point.y = 10 12 | 13 | assert not cffi_mixed.lib.is_in_range(point, 14) 14 | assert cffi_mixed.lib.is_in_range(point, 15) 15 | 16 | 17 | def test_ffi(): 18 | point = cffi_mixed.ffi.new("Point *", (10, 20)) 19 | assert point.x == 10 20 | assert point.y == 20 21 | 22 | 23 | def test_line(): 24 | line = Line(2, 5, 6, 8) 25 | assert line.length() == 5 26 | assert str(line) == "Line from (2.0,5.0) to (6.0,8.0)" 27 | -------------------------------------------------------------------------------- /test-crates/cffi-mixed/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest 8 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/.gitignore: -------------------------------------------------------------------------------- 1 | cffi_pure/cffi_pure 2 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "cffi-pure" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cffi-pure" 3 | version = "0.1.0" 4 | authors = ["Armin Ronacher "] 5 | edition = "2021" 6 | 7 | [lib] 8 | name = "cffi_pure" 9 | crate-type = ["cdylib"] 10 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/Readme.md: -------------------------------------------------------------------------------- 1 | # cffi-pure 2 | 3 | A package for testing a crate with cffi bindings with maturin. 4 | 5 | Read the [cffi guide](https://cffi.readthedocs.io/en/latest/index.html) to learn how to use the generated `ffi` and `lib` objects. 6 | 7 | ## Usage 8 | 9 | ```bash 10 | pip install . 11 | ``` 12 | 13 | ```python 14 | import cffi_pure 15 | 16 | point = cffi_pure.lib.get_origin() 17 | point.x = 10 18 | point.y = 10 19 | assert cffi_pure.lib.is_in_range(point, 15) 20 | ``` 21 | 22 | ## Testing 23 | 24 | Install tox: 25 | 26 | ```bash 27 | pip install tox 28 | ``` 29 | 30 | Run it: 31 | 32 | ```bash 33 | tox 34 | ``` 35 | 36 | The tests are in `test_cffi_pure.py`, while the configuration is in tox.ini 37 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import cffi_pure 4 | 5 | point = cffi_pure.lib.get_origin() 6 | point.x = 10 7 | point.y = 10 8 | assert cffi_pure.lib.is_in_range(point, 15) 9 | 10 | print("SUCCESS") 11 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "cffi-pure" 7 | dependencies = ["cffi"] 8 | dynamic = ["version"] 9 | 10 | [tool.maturin] 11 | bindings = "cffi" 12 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/requirements_test.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | cffi 3 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | pub struct Point { 3 | pub x: f32, 4 | pub y: f32, 5 | } 6 | 7 | #[repr(u32)] 8 | pub enum Foo { 9 | A = 1, 10 | B, 11 | C, 12 | } 13 | 14 | #[no_mangle] 15 | pub unsafe extern "C" fn get_origin() -> Point { 16 | Point { x: 0.0, y: 0.0 } 17 | } 18 | 19 | #[no_mangle] 20 | pub unsafe extern "C" fn is_in_range(point: Point, range: f32) -> bool { 21 | (point.x.powi(2) + point.y.powi(2)).sqrt() <= range 22 | } 23 | 24 | #[no_mangle] 25 | pub unsafe extern "C" fn print_foo(foo: *const Foo) { 26 | println!( 27 | "{}", 28 | match *foo { 29 | Foo::A => "a", 30 | Foo::B => "b", 31 | Foo::C => "c", 32 | } 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/test_cffi_pure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import cffi_pure 4 | 5 | 6 | def test_range(): 7 | point = cffi_pure.lib.get_origin() 8 | point.x = 10 9 | point.y = 10 10 | 11 | assert not cffi_pure.lib.is_in_range(point, 14) 12 | assert cffi_pure.lib.is_in_range(point, 15) 13 | 14 | 15 | def test_ffi(): 16 | point = cffi_pure.ffi.new("Point *", (10, 20)) 17 | assert point.x == 10 18 | assert point.y == 20 19 | -------------------------------------------------------------------------------- /test-crates/cffi-pure/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest 8 | -------------------------------------------------------------------------------- /test-crates/hello-world/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "hello-world" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /test-crates/hello-world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-world" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | # Test references to out-of-project files 7 | readme = "../../README.md" 8 | default-run = "hello-world" 9 | 10 | [dependencies] 11 | -------------------------------------------------------------------------------- /test-crates/hello-world/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | from subprocess import check_output 2 | 3 | 4 | def main(): 5 | output = check_output(["hello-world"]).decode("utf-8").strip() 6 | if not output == "Hello, world!": 7 | raise Exception(output) 8 | 9 | output = check_output(["foo"]).decode("utf-8").strip() 10 | if not output == "🦀 Hello, world! 🦀": 11 | raise Exception(output) 12 | print("SUCCESS") 13 | 14 | 15 | if __name__ == "__main__": 16 | main() 17 | -------------------------------------------------------------------------------- /test-crates/hello-world/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [tool.maturin] 6 | bindings = "bin" 7 | 8 | [[tool.maturin.targets]] 9 | name = "hello-world" 10 | bindings = "bin" 11 | 12 | [[tool.maturin.targets]] 13 | name = "foo" 14 | -------------------------------------------------------------------------------- /test-crates/hello-world/src/bin/foo.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("🦀 Hello, world! 🦀"); 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/hello-world/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/lib_with_disallowed_lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lib_with_disallowed_lib" 3 | version = "0.1.0" 4 | authors = ["messense "] 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | libz-sys = { version = "1.1.2", default-features = false } 12 | pyo3 = { version = "0.24.0", features = ["extension-module"] } 13 | -------------------------------------------------------------------------------- /test-crates/lib_with_disallowed_lib/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/lib_with_disallowed_lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::os::raw::c_ulong; 2 | 3 | use pyo3::prelude::*; 4 | 5 | #[link(name = "z")] 6 | extern "C" { 7 | fn gzflags() -> c_ulong; 8 | } 9 | 10 | #[pyfunction] 11 | fn add(x: usize, y: usize) -> usize { 12 | let _version = unsafe { libz_sys::zlibVersion() }; 13 | let _flags = unsafe { gzflags() }; 14 | let sum = x + y; 15 | sum 16 | } 17 | 18 | #[pymodule] 19 | fn lib_with_disallowed_lib(m: &Bound<'_, PyModule>) -> PyResult<()> { 20 | m.add_wrapped(wrap_pyfunction!(add))?; 21 | 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /test-crates/lib_with_path_dep/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lib_with_path_dep" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | pyo3 = { version = "0.24.0", features = ["extension-module"] } 12 | some_path_dep = { path = "../some_path_dep" } 13 | -------------------------------------------------------------------------------- /test-crates/lib_with_path_dep/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/lib_with_path_dep/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pyfunction] 4 | fn add(x: usize, y: usize) -> usize { 5 | let sum = some_path_dep::add(x, y); 6 | debug_assert!(some_path_dep::is_sum(x, y, sum)); 7 | sum 8 | } 9 | 10 | #[pymodule] 11 | fn lib_with_path_dep(m: &Bound<'_, PyModule>) -> PyResult<()> { 12 | m.add_wrapped(wrap_pyfunction!(add))?; 13 | Ok(()) 14 | } 15 | -------------------------------------------------------------------------------- /test-crates/lib_with_path_dep/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | # The problem with testing this is that we need to go through the PEP 517 so we need a wheel of maturin, 6 | # which makes everything complex and slow 7 | cd "$(git rev-parse --show-toplevel)" # Go to project root 8 | 9 | pip uninstall -y lib_with_path_dep 2> /dev/null 10 | # Make sure it's actually removed 11 | python -c "from lib_with_path_dep import add; assert add(2,2)==4" 2> /dev/null && exit 1 || true 12 | 13 | # Build maturin wheel 14 | cargo run -- build -b bin --strip --manylinux off 15 | cargo run -- pep517 write-sdist --manifest-path test-crates/lib_with_path_dep/Cargo.toml --sdist-directory test-crates/lib_with_path_dep/target/wheels 16 | # Slower alternative: cargo run -- build -m test-crates/lib_with_path_dep/Cargo.toml -i python 17 | # See https://github.com/pypa/pip/issues/6041 18 | 19 | # First, use the maturin wheel we just build 20 | # Then install lib_with_path_dep from the sdist we build 21 | pip install \ 22 | --find-links target/wheels/ \ 23 | --force-reinstall --no-binary lib_with_path_dep --find-links test-crates/lib_with_path_dep/target/wheels lib_with_path_dep 24 | python -c "from lib_with_path_dep import add; assert add(2,2)==4" 25 | -------------------------------------------------------------------------------- /test-crates/license-test/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | AUTHORS 2 | -------------------------------------------------------------------------------- /test-crates/license-test/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "license-test" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /test-crates/license-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "license-test" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | license = "MIT" 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /test-crates/license-test/LICENCE.txt: -------------------------------------------------------------------------------- 1 | LICENCE 2 | -------------------------------------------------------------------------------- /test-crates/license-test/LICENSE: -------------------------------------------------------------------------------- 1 | LICENSE 2 | -------------------------------------------------------------------------------- /test-crates/license-test/NOTICE.md: -------------------------------------------------------------------------------- 1 | # NOTICE 2 | -------------------------------------------------------------------------------- /test-crates/license-test/_vendor/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | AUTHORS 2 | -------------------------------------------------------------------------------- /test-crates/license-test/_vendor/COPYING.md: -------------------------------------------------------------------------------- 1 | # COPYING 2 | -------------------------------------------------------------------------------- /test-crates/license-test/_vendor/LICENCE: -------------------------------------------------------------------------------- 1 | LICENCE 2 | -------------------------------------------------------------------------------- /test-crates/license-test/_vendor/LICENSE-APACHE.txt: -------------------------------------------------------------------------------- 1 | LICENSE-APACHE 2 | -------------------------------------------------------------------------------- /test-crates/license-test/_vendor/NOTICE: -------------------------------------------------------------------------------- 1 | NOTICE 2 | -------------------------------------------------------------------------------- /test-crates/license-test/_vendor/nested/LICENSE-BSD: -------------------------------------------------------------------------------- 1 | LICENSE-BSD 2 | -------------------------------------------------------------------------------- /test-crates/license-test/_vendor/nested/NOTICE.md: -------------------------------------------------------------------------------- 1 | # NOTICE 2 | -------------------------------------------------------------------------------- /test-crates/license-test/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | from subprocess import check_output 2 | 3 | 4 | def main(): 5 | output = check_output(["license-test"]).decode("utf-8").strip() 6 | if not output == "Hello, world!": 7 | raise Exception(output) 8 | print("SUCCESS") 9 | 10 | 11 | if __name__ == "__main__": 12 | main() 13 | -------------------------------------------------------------------------------- /test-crates/license-test/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "license-test" 7 | license = { file = "LICENCE.txt" } 8 | dynamic = ["version"] 9 | 10 | [tool.maturin] 11 | bindings = "bin" 12 | -------------------------------------------------------------------------------- /test-crates/license-test/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/pyo3-abi3-without-version/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pyo3-abi3-without-version" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | pyo3 = { version = "0.24.1", features = ["abi3", "extension-module"] } 9 | 10 | [lib] 11 | name = "pyo3_abi3_without_version" 12 | crate-type = ["cdylib"] 13 | -------------------------------------------------------------------------------- /test-crates/pyo3-abi3-without-version/src/lib.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-abi3-without-version/src/lib.rs -------------------------------------------------------------------------------- /test-crates/pyo3-bin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pyo3-bin" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | pyo3 = { version = "0.24.0", features = ["auto-initialize"] } 10 | -------------------------------------------------------------------------------- /test-crates/pyo3-bin/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import sys 4 | from subprocess import check_output 5 | 6 | 7 | def main(): 8 | if platform.system().lower() == "windows": 9 | # Add sys.base_prefix which contains python3y.dll to PATH 10 | # otherwise running `pyo3-bin` might return exit code 3221225781 11 | path = os.environ["PATH"] 12 | path = path + os.pathsep + sys.base_prefix 13 | os.environ["PATH"] = path 14 | 15 | output = check_output(["pyo3-bin"]).decode("utf-8").strip() 16 | if not output == "Hello, world!": 17 | raise Exception(output) 18 | print("SUCCESS") 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /test-crates/pyo3-bin/src/main.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | fn main() -> PyResult<()> { 4 | Python::with_gil(|py| { 5 | let builtins = py.import("builtins")?; 6 | let total: i32 = builtins.getattr("sum")?.call1((vec![1, 2, 3],))?.extract()?; 7 | assert_eq!(total, 6); 8 | println!("Hello, world!"); 9 | Ok(()) 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /test-crates/pyo3-feature/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["konstin "] 3 | name = "pyo3-feature" 4 | version = "0.7.3" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | pyo3 = { version = "0.24.0", optional = true } 9 | -------------------------------------------------------------------------------- /test-crates/pyo3-feature/Readme.md: -------------------------------------------------------------------------------- 1 | A crate where pyo3 is an optional feature 2 | -------------------------------------------------------------------------------- /test-crates/pyo3-feature/src/lib.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-feature/src/lib.rs -------------------------------------------------------------------------------- /test-crates/pyo3-ffi-pure/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "libc" 7 | version = "0.2.147" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 10 | 11 | [[package]] 12 | name = "once_cell" 13 | version = "1.18.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 16 | 17 | [[package]] 18 | name = "pyo3-build-config" 19 | version = "0.18.3" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "9cb946f5ac61bb61a5014924910d936ebd2b23b705f7a4a3c40b05c720b079a3" 22 | dependencies = [ 23 | "once_cell", 24 | "target-lexicon", 25 | ] 26 | 27 | [[package]] 28 | name = "pyo3-ffi" 29 | version = "0.18.3" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "fd4d7c5337821916ea2a1d21d1092e8443cf34879e53a0ac653fbb98f44ff65c" 32 | dependencies = [ 33 | "libc", 34 | "pyo3-build-config", 35 | ] 36 | 37 | [[package]] 38 | name = "pyo3-ffi-pure" 39 | version = "1.0.0" 40 | dependencies = [ 41 | "pyo3-ffi", 42 | ] 43 | 44 | [[package]] 45 | name = "target-lexicon" 46 | version = "0.12.11" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" 49 | -------------------------------------------------------------------------------- /test-crates/pyo3-ffi-pure/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pyo3-ffi-pure" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | pyo3-ffi = { version = "0.18.1", features = ["abi3-py37", "extension-module"] } 8 | 9 | [lib] 10 | name = "pyo3_ffi_pure" 11 | crate-type = ["cdylib"] 12 | -------------------------------------------------------------------------------- /test-crates/pyo3-ffi-pure/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022-present maturin contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /test-crates/pyo3-ffi-pure/README.md: -------------------------------------------------------------------------------- 1 | # pyo3-ffi-pure 2 | 3 | A package with pyo3-ffi bindings for testing maturin. 4 | 5 | ## Usage 6 | 7 | ```python 8 | import pyo3_ffi_pure 9 | assert pyo3_ffi_pure.sum(2, 40) == 42 10 | ``` 11 | 12 | ## Testing 13 | 14 | Install `pytest` and run: 15 | 16 | ```bash 17 | pytest -v test_pyo3_ffi_pure.py 18 | ``` 19 | -------------------------------------------------------------------------------- /test-crates/pyo3-ffi-pure/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import pyo3_ffi_pure 3 | 4 | assert pyo3_ffi_pure.sum(2, 40) == 42 5 | 6 | print("SUCCESS") 7 | -------------------------------------------------------------------------------- /test-crates/pyo3-ffi-pure/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pyo3-ffi-pure" 7 | classifiers = [ 8 | "Programming Language :: Rust" 9 | ] 10 | description = "Tests compilation of packages using pyo3-ffi bindings" 11 | readme = "README.md" 12 | maintainers = [ 13 | {name = "messense", email = "messense@icloud.com"} 14 | ] 15 | license = { file = "LICENSE" } 16 | dynamic = ["version"] 17 | -------------------------------------------------------------------------------- /test-crates/pyo3-ffi-pure/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3_ffi::*; 2 | use std::os::raw::c_char; 3 | 4 | #[allow(non_snake_case)] 5 | #[no_mangle] 6 | pub unsafe extern "C" fn PyInit_pyo3_ffi_pure() -> *mut PyObject { 7 | let module_name = "pyo3_ffi_pure\0".as_ptr() as *const c_char; 8 | let init = PyModuleDef { 9 | m_base: PyModuleDef_HEAD_INIT, 10 | m_name: module_name, 11 | m_doc: std::ptr::null(), 12 | m_size: 0, 13 | m_methods: std::ptr::null_mut(), 14 | m_slots: std::ptr::null_mut(), 15 | m_traverse: None, 16 | m_clear: None, 17 | m_free: None, 18 | }; 19 | let mptr = PyModule_Create(Box::into_raw(Box::new(init))); 20 | 21 | let wrapped_sum = PyMethodDef { 22 | ml_name: "sum\0".as_ptr() as *const c_char, 23 | ml_meth: PyMethodDefPointer { 24 | PyCFunctionWithKeywords: sum, 25 | }, 26 | ml_flags: METH_VARARGS | METH_KEYWORDS, 27 | ml_doc: std::ptr::null_mut(), 28 | }; 29 | PyModule_AddObject( 30 | mptr, 31 | "sum\0".as_ptr() as *const c_char, 32 | PyCFunction_NewEx( 33 | Box::into_raw(Box::new(wrapped_sum)), 34 | std::ptr::null_mut(), 35 | PyUnicode_InternFromString(module_name), 36 | ), 37 | ); 38 | 39 | mptr 40 | } 41 | 42 | #[no_mangle] 43 | pub unsafe extern "C" fn sum( 44 | _self: *mut PyObject, 45 | args: *mut PyObject, 46 | _kwds: *mut PyObject, 47 | ) -> *mut PyObject { 48 | // this is a minimal test of compilation, not good example code 49 | let val_a = PyTuple_GetItem(args, 0); 50 | let val_b = PyTuple_GetItem(args, 1); 51 | let res: i64 = PyLong_AsLongLong(val_a) + PyLong_AsLongLong(val_b); 52 | PyLong_FromLongLong(res) 53 | } 54 | -------------------------------------------------------------------------------- /test-crates/pyo3-ffi-pure/test_pyo3_ffi_pure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_ffi_pure 4 | 5 | 6 | def test_static(): 7 | assert pyo3_ffi_pure.sum(2, 40) == 42 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cdo] 2 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Kevin Patterson "] 3 | name = "pyo3-mixed-implicit" 4 | version = "2.1.3" 5 | description = "Implements a dummy function combining rust and python" 6 | readme = "README.md" 7 | edition = "2021" 8 | 9 | [dependencies] 10 | pyo3 = { version = "0.24.0", features = ["extension-module"] } 11 | 12 | [lib] 13 | name = "pyo3_mixed_implicit" 14 | crate-type = ["cdylib"] 15 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/README.md: -------------------------------------------------------------------------------- 1 | # pyo3-mixed-implicit 2 | 3 | A package for testing maturin with a mixed pyo3/python project with an implicit namespace package and Rust submodule. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | pip install . 9 | ``` 10 | 11 | ```python 12 | import pyo3_mixed_implicit 13 | assert pyo3_mixed_implicit.some_rust.get_22() == 22 14 | ``` 15 | 16 | ## Testing 17 | 18 | Install tox: 19 | 20 | ```bash 21 | pip install tox 22 | ``` 23 | 24 | Run it: 25 | 26 | ```bash 27 | tox 28 | ``` 29 | 30 | The tests are in `tests/test_pyo3_mixed_implicit.py`, while the configuration is in tox.ini 31 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_implicit.some_rust as some_rust 4 | 5 | assert some_rust.get_22() == 22 6 | assert some_rust.double(lambda: 4) == 8 7 | 8 | print("SUCCESS") 9 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pyo3_mixed_implicit" 7 | classifiers = [ 8 | "Programming Language :: Python", 9 | "Programming Language :: Rust" 10 | ] 11 | dynamic = ["version"] 12 | 13 | [tool.maturin] 14 | features = ["pyo3/extension-module"] 15 | module-name = "pyo3_mixed_implicit.some_rust.rust" 16 | python-source = "python" 17 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/python/pyo3_mixed_implicit/some_rust/__init__.py: -------------------------------------------------------------------------------- 1 | from .rust import get_22 2 | from .double import double 3 | 4 | __all__ = ["get_22", "double"] 5 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/python/pyo3_mixed_implicit/some_rust/double.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | 4 | def double(fn: Callable[[], int]) -> int: 5 | return 2 * fn() 6 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pyfunction] 4 | fn get_22() -> usize { 5 | 22 6 | } 7 | 8 | #[pymodule] 9 | fn rust(m: &Bound<'_, PyModule>) -> PyResult<()> { 10 | m.add_wrapped(wrap_pyfunction!(get_22))?; 11 | 12 | Ok(()) 13 | } 14 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/tests/test_pyo3_mixed_implicit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_implicit.some_rust as some_rust 4 | 5 | 6 | def test_get_rust_and_python(): 7 | assert some_rust.get_22() == 22 8 | assert some_rust.double(lambda: 4) == 8 9 | 10 | 11 | print("SUCCESS") 12 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-implicit/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest tests/ 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cdo] 2 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [] 3 | name = "pyo3-mixed-include-exclude" 4 | version = "2.1.3" 5 | description = "Implements a dummy function combining rust and python" 6 | edition = "2021" 7 | 8 | [dependencies] 9 | pyo3 = { version = "0.24.0", features = [ 10 | "extension-module", 11 | "generate-import-lib", 12 | ] } 13 | 14 | [lib] 15 | name = "pyo3_mixed_include_exclude" 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/README.md: -------------------------------------------------------------------------------- 1 | # pyo3-mixed-include-exclude 2 | 3 | A package for testing maturin with a mixed pyo3/python project with include and exclude configurations. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | pip install . 9 | ``` 10 | 11 | ```python 12 | import pyo3_mixed_include_exclude 13 | assert pyo3_mixed_include_exclude.get_42() == 42 14 | ``` 15 | 16 | ## Testing 17 | 18 | Install tox: 19 | 20 | ```bash 21 | pip install tox 22 | ``` 23 | 24 | Run it: 25 | 26 | ```bash 27 | tox 28 | ``` 29 | 30 | The tests are in `test_pyo3_mixed_include_exclude.py`, while the configuration is in tox.ini 31 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_include_exclude 4 | 5 | assert pyo3_mixed_include_exclude.get_42() == 42 6 | 7 | print("SUCCESS") 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/pyo3_mixed_include_exclude/.gitignore: -------------------------------------------------------------------------------- 1 | include_this_file 2 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/pyo3_mixed_include_exclude/__init__.py: -------------------------------------------------------------------------------- 1 | from .python_module.double import double 2 | from .pyo3_mixed_include_exclude import get_21 3 | 4 | 5 | def get_42() -> int: 6 | return double(get_21) 7 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/pyo3_mixed_include_exclude/exclude_this_file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-mixed-include-exclude/pyo3_mixed_include_exclude/exclude_this_file -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/pyo3_mixed_include_exclude/include_this_file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-mixed-include-exclude/pyo3_mixed_include_exclude/include_this_file -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/pyo3_mixed_include_exclude/python_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-mixed-include-exclude/pyo3_mixed_include_exclude/python_module/__init__.py -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/pyo3_mixed_include_exclude/python_module/double.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | 4 | def double(fn: Callable[[], int]) -> int: 5 | return 2 * fn() 6 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pyo3-mixed-include-exclude" 7 | classifiers = ["Programming Language :: Python", "Programming Language :: Rust"] 8 | requires-python = ">=3.7" 9 | dynamic = ["version"] 10 | 11 | [project.scripts] 12 | get_42 = "pyo3_mixed_include_exclude:get_42" 13 | 14 | [tool.maturin] 15 | include = [ 16 | "pyo3_mixed_include_exclude/include_this_file", 17 | "missing", 18 | "README.md", 19 | ] 20 | exclude = [ 21 | "pyo3_mixed_include_exclude/exclude_this_file", 22 | "pyo3_mixed_include_exclude/.gitignore", 23 | "tests/**/*", 24 | "unused", 25 | ] 26 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pyfunction] 4 | fn get_21() -> usize { 5 | 21 6 | } 7 | 8 | #[pymodule] 9 | fn pyo3_mixed_include_exclude(m: &Bound<'_, PyModule>) -> PyResult<()> { 10 | m.add_wrapped(wrap_pyfunction!(get_21))?; 11 | 12 | Ok(()) 13 | } 14 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/tests/test_pyo3_mixed_include_exclude.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_include_exclude 4 | 5 | 6 | def test_get_42(): 7 | assert pyo3_mixed_include_exclude.get_42() == 42 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-include-exclude/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest tests/ 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cdo] 2 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["konstin "] 3 | name = "pyo3-mixed-py-subdir" 4 | version = "2.1.3" 5 | description = "Implements a dummy function combining rust and python" 6 | readme = "README.md" 7 | edition = "2021" 8 | 9 | [dependencies] 10 | pyo3 = { version = "0.24.0", features = ["extension-module"] } 11 | 12 | [lib] 13 | name = "pyo3_mixed_py_subdir" 14 | crate-type = ["cdylib"] 15 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/README.md: -------------------------------------------------------------------------------- 1 | # pyo3-mixed 2 | 3 | A package for testing maturin with a mixed pyo3/python project and a non-default package name. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | pip install . 9 | ``` 10 | 11 | ```python 12 | import pyo3_mixed_py_subdir 13 | assert pyo3_mixed_py_subdir.get_42() == 42 14 | ``` 15 | 16 | ## Testing 17 | 18 | Install tox: 19 | 20 | ```bash 21 | pip install tox 22 | ``` 23 | 24 | Run it: 25 | 26 | ```bash 27 | tox 28 | ``` 29 | 30 | The tests are in `test_pyo3_mixed.py`, while the configuration is in tox.ini 31 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_py_subdir as pyo3_mixed 4 | 5 | assert pyo3_mixed.get_42() == 42 6 | 7 | print("SUCCESS") 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pyo3-mixed-py-subdir" 7 | classifiers = [ 8 | "Programming Language :: Python", 9 | "Programming Language :: Rust" 10 | ] 11 | requires-python = ">=3.6" 12 | dynamic = ["version"] 13 | 14 | [project.scripts] 15 | get_42 = "pyo3_mixed_py_subdir:get_42" 16 | 17 | [tool.maturin] 18 | module-name = "pyo3_mixed_py_subdir._pyo3_mixed" 19 | python-source = "python" 20 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/python/pyo3_mixed_py_subdir/__init__.py: -------------------------------------------------------------------------------- 1 | from .python_module.double import double 2 | from ._pyo3_mixed import get_21 3 | 4 | 5 | def get_42() -> int: 6 | return double(get_21) 7 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/python/pyo3_mixed_py_subdir/python_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-mixed-py-subdir/python/pyo3_mixed_py_subdir/python_module/__init__.py -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/python/pyo3_mixed_py_subdir/python_module/double.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | 4 | def double(fn: Callable[[], int]) -> int: 5 | return 2 * fn() 6 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pyfunction] 4 | fn get_21() -> usize { 5 | 21 6 | } 7 | 8 | #[pymodule] 9 | fn _pyo3_mixed(m: &Bound<'_, PyModule>) -> PyResult<()> { 10 | m.add_wrapped(wrap_pyfunction!(get_21))?; 11 | 12 | Ok(()) 13 | } 14 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/test_pyo3_mixed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_py_subdir as pyo3_mixed 4 | 5 | 6 | def test_get_42(): 7 | assert pyo3_mixed.get_42() == 42 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-py-subdir/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cdo] 2 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/README.md: -------------------------------------------------------------------------------- 1 | # pyo3-mixed src layout 2 | 3 | A package for testing maturin with a src layout mixed pyo3/python project. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | pip install . 9 | ``` 10 | 11 | ```python 12 | import pyo3_mixed_src 13 | assert pyo3_mixed_src.get_42() == 42 14 | ``` 15 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_src as pyo3_mixed 4 | 5 | assert pyo3_mixed.get_42() == 42 6 | 7 | print("SUCCESS") 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pyo3-mixed-src" 7 | classifiers = [ 8 | "Programming Language :: Python", 9 | "Programming Language :: Rust" 10 | ] 11 | requires-python = ">=3.7" 12 | dynamic = ["version"] 13 | 14 | [project.scripts] 15 | get_42 = "pyo3_mixed_src:get_42" 16 | 17 | [tool.maturin] 18 | python-packages = ["pyo3_mixed_src", "tests"] 19 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["konstin "] 3 | name = "pyo3-mixed-src" 4 | version = "2.1.3" 5 | description = "Implements a dummy function combining rust and python" 6 | edition = "2021" 7 | 8 | [dependencies] 9 | pyo3 = { version = "0.24.0", features = [ 10 | "extension-module", 11 | "generate-import-lib", 12 | ] } 13 | 14 | [lib] 15 | name = "pyo3_mixed_src" 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pyfunction] 4 | fn get_21() -> usize { 5 | 21 6 | } 7 | 8 | #[pymodule] 9 | fn pyo3_mixed_src(m: &Bound<'_, PyModule>) -> PyResult<()> { 10 | m.add_wrapped(wrap_pyfunction!(get_21))?; 11 | 12 | Ok(()) 13 | } 14 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/src/pyo3_mixed_src/__init__.py: -------------------------------------------------------------------------------- 1 | from .python_module.double import double 2 | from .pyo3_mixed_src import get_21 3 | 4 | 5 | def get_42() -> int: 6 | return double(get_21) 7 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/src/pyo3_mixed_src/python_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-mixed-src/src/pyo3_mixed_src/python_module/__init__.py -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/src/pyo3_mixed_src/python_module/double.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | 4 | def double(fn: Callable[[], int]) -> int: 5 | return 2 * fn() 6 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/src/tests/test_pyo3_mixed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_src as pyo3_mixed 4 | 5 | 6 | def test_get_42(): 7 | assert pyo3_mixed.get_42() == 42 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-src/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest src/tests/ 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cdo] 2 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["konstin "] 3 | name = "pyo3-mixed-submodule" 4 | version = "2.1.3" 5 | description = "Implements a dummy function combining rust and python" 6 | readme = "README.md" 7 | edition = "2021" 8 | 9 | [dependencies] 10 | pyo3 = { version = "0.24.0", features = ["extension-module"] } 11 | 12 | [lib] 13 | name = "pyo3_mixed_submodule" 14 | crate-type = ["cdylib"] 15 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/README.md: -------------------------------------------------------------------------------- 1 | # pyo3-mixed-submodule 2 | 3 | A package for testing maturin with a mixed pyo3/python project with Rust submodule. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | pip install . 9 | ``` 10 | 11 | ```python 12 | import pyo3_mixed_submodule 13 | assert pyo3_mixed_submodule.get_42() == 42 14 | ``` 15 | 16 | ## Testing 17 | 18 | Install tox: 19 | 20 | ```bash 21 | pip install tox 22 | ``` 23 | 24 | Run it: 25 | 26 | ```bash 27 | tox 28 | ``` 29 | 30 | The tests are in `tests/test_pyo3_mixed_submodule.py`, while the configuration is in tox.ini 31 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_submodule 4 | 5 | assert pyo3_mixed_submodule.get_42() == 42 6 | 7 | print("SUCCESS") 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/__init__.py: -------------------------------------------------------------------------------- 1 | from .python_module.double import double 2 | from .rust_module.rust import get_21 3 | 4 | 5 | def get_42() -> int: 6 | return double(get_21) 7 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/__init__.py -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/python_module/double.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | 4 | def double(fn: Callable[[], int]) -> int: 5 | return 2 * fn() 6 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/rust_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-mixed-submodule/pyo3_mixed_submodule/rust_module/__init__.py -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pyo3-mixed-submodule" 7 | classifiers = [ 8 | "Programming Language :: Python", 9 | "Programming Language :: Rust" 10 | ] 11 | dynamic = ["version"] 12 | 13 | [tool.maturin] 14 | module-name = "pyo3_mixed_submodule.rust_module.rust" 15 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pyfunction] 4 | fn get_21() -> usize { 5 | 21 6 | } 7 | 8 | #[pymodule] 9 | fn rust(m: &Bound<'_, PyModule>) -> PyResult<()> { 10 | m.add_wrapped(wrap_pyfunction!(get_21))?; 11 | 12 | Ok(()) 13 | } 14 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/tests/test_pyo3_mixed_submodule.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_submodule 4 | 5 | 6 | def test_get_42(): 7 | assert pyo3_mixed_submodule.get_42() == 42 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-submodule/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest tests/ 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-with-path-dep/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cdo] 2 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-with-path-dep/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [] 3 | name = "pyo3-mixed-with-path-dep" 4 | version = "2.1.3" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | pyo3 = { version = "0.24.0", features = [ 9 | "extension-module", 10 | "generate-import-lib", 11 | ] } 12 | some_path_dep = { path = "../some_path_dep" } 13 | 14 | [lib] 15 | name = "pyo3_mixed_with_path_dep" 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-with-path-dep/README.md: -------------------------------------------------------------------------------- 1 | # pyo3-mixed 2 | 3 | A package for testing maturin with a mixed pyo3/python project. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | pip install . 9 | ``` 10 | 11 | ```python 12 | import pyo3_mixed_with_path_dep 13 | assert pyo3_mixed_with_path_dep.get_42() == 42 14 | ``` 15 | 16 | ## Testing 17 | 18 | Install tox: 19 | 20 | ```bash 21 | pip install tox 22 | ``` 23 | 24 | Run it: 25 | 26 | ```bash 27 | tox 28 | ``` 29 | 30 | The tests are in `tests/test_pyo3_mixed_with_path_dep.py`, while the configuration is in tox.ini 31 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-with-path-dep/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import pyo3_mixed_with_path_dep 3 | 4 | assert pyo3_mixed_with_path_dep.get_42() == 42, "get_42 did not return 42" 5 | 6 | assert pyo3_mixed_with_path_dep.is_half(21, 42), "21 is not half of 42" 7 | assert not pyo3_mixed_with_path_dep.is_half(21, 73), "21 is half of 63" 8 | 9 | print("SUCCESS") 10 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-with-path-dep/pyo3_mixed_with_path_dep/__init__.py: -------------------------------------------------------------------------------- 1 | from .pyo3_mixed_with_path_dep import get_21, add_21, is_half 2 | 3 | __all__ = ["get_21", "add_21", "is_half", "get_42"] 4 | 5 | 6 | def get_42() -> int: 7 | return add_21(get_21()) 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-with-path-dep/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pyo3-mixed-with-path-dep" 7 | classifiers = [ 8 | "Programming Language :: Python", 9 | "Programming Language :: Rust" 10 | ] 11 | requires-python = ">=3.7" 12 | dynamic = ["version"] 13 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-with-path-dep/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | use some_path_dep::{add, is_sum}; 3 | 4 | #[pyfunction] 5 | fn get_21() -> usize { 6 | 21 7 | } 8 | 9 | #[pyfunction] 10 | fn add_21(num: usize) -> usize { 11 | add(num, get_21()) 12 | } 13 | 14 | #[pyfunction] 15 | fn is_half(a: usize, b: usize) -> bool { 16 | is_sum(a, a, b) 17 | } 18 | 19 | 20 | #[pymodule] 21 | fn pyo3_mixed_with_path_dep(m: &Bound<'_, PyModule>) -> PyResult<()> { 22 | m.add_wrapped(wrap_pyfunction!(get_21))?; 23 | m.add_wrapped(wrap_pyfunction!(add_21))?; 24 | m.add_wrapped(wrap_pyfunction!(is_half))?; 25 | 26 | Ok(()) 27 | } 28 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-with-path-dep/tests/test_pyo3_mixed_with_path_dep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_with_path_dep 4 | 5 | 6 | def test_get_42(): 7 | assert pyo3_mixed_with_path_dep.get_42() == 42 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-with-path-dep/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest tests/ 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/README.md: -------------------------------------------------------------------------------- 1 | # pyo3-mixed src layout 2 | 3 | A package for testing maturin with a nested workspace. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | pip install . 9 | ``` 10 | 11 | ```python 12 | import pyo3_mixed_workspace 13 | assert pyo3_mixed_workspace.get_42() == 42 14 | ``` 15 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_workspace as pyo3_mixed 4 | 5 | assert pyo3_mixed.get_42() == 42 6 | 7 | print("SUCCESS") 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pyo3-mixed-workspace" 7 | classifiers = [ 8 | "Programming Language :: Python", 9 | "Programming Language :: Rust" 10 | ] 11 | requires-python = ">=3.7" 12 | dynamic = ["version"] 13 | 14 | [project.scripts] 15 | get_42 = "pyo3_mixed_workspace:get_42" 16 | 17 | [tool.maturin] 18 | python-packages = ["pyo3_mixed_workspace", "tests"] 19 | module-name = "pyo3_mixed_workspace.pyo3_mixed_workspace_py" 20 | manifest-path = "rust/python/pyo3-mixed-workspace-py/Cargo.toml" 21 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "pyo3-mixed-workspace", 5 | "python/pyo3-mixed-workspace-py", 6 | ] 7 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/rust/pyo3-mixed-workspace/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pyo3-mixed-workspace" 3 | version = "2.1.3" 4 | description = "Implements a dummy function combining rust and python" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/rust/pyo3-mixed-workspace/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn get_21_lib() -> usize { 2 | 21 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/rust/python/pyo3-mixed-workspace-py/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["konstin "] 3 | name = "pyo3-mixed-workspace-py" 4 | version = "2.1.3" 5 | description = "Implements a dummy function combining rust and python" 6 | edition = "2021" 7 | 8 | [dependencies] 9 | pyo3-mixed-workspace = { path = "../../pyo3-mixed-workspace" } 10 | pyo3 = { version = "0.24.0", features = [ 11 | "extension-module", 12 | "generate-import-lib", 13 | ] } 14 | 15 | [lib] 16 | name = "pyo3_mixed_workspace_py" 17 | crate-type = ["cdylib"] 18 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/rust/python/pyo3-mixed-workspace-py/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | use pyo3_mixed_workspace::get_21_lib; 4 | 5 | #[pyfunction] 6 | fn get_21() -> usize { 7 | get_21_lib() 8 | } 9 | 10 | #[pymodule] 11 | fn pyo3_mixed_workspace_py(m: &Bound<'_, PyModule>) -> PyResult<()> { 12 | m.add_function(wrap_pyfunction!(get_21, m)?)?; 13 | 14 | Ok(()) 15 | } 16 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/src/pyo3_mixed_workspace/__init__.py: -------------------------------------------------------------------------------- 1 | from .python_module.double import double 2 | from .pyo3_mixed_workspace_py import get_21 3 | 4 | 5 | def get_42() -> int: 6 | return double(get_21) 7 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/src/pyo3_mixed_workspace/python_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-mixed-workspace/src/pyo3_mixed_workspace/python_module/__init__.py -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/src/pyo3_mixed_workspace/python_module/double.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | 4 | def double(fn: Callable[[], int]) -> int: 5 | return 2 * fn() 6 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/src/tests/test_pyo3_mixed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed_workspace as pyo3_mixed 4 | 5 | 6 | def test_get_42(): 7 | assert pyo3_mixed.get_42() == 42 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed-workspace/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest src/tests/ 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cdo] 2 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["konstin "] 3 | name = "pyo3-mixed" 4 | version = "2.1.5" 5 | description = "Implements a dummy function combining rust and python" 6 | edition = "2021" 7 | 8 | [dependencies] 9 | pyo3 = { version = "0.24.0", features = [ 10 | "extension-module", 11 | "generate-import-lib", 12 | ] } 13 | 14 | [lib] 15 | name = "pyo3_mixed" 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/README.md: -------------------------------------------------------------------------------- 1 | # pyo3-mixed 2 | 3 | A package for testing maturin with a mixed pyo3/python project. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | pip install . 9 | ``` 10 | 11 | ```python 12 | import pyo3_mixed 13 | assert pyo3_mixed.get_42() == 42 14 | ``` 15 | 16 | ## Testing 17 | 18 | Install tox: 19 | 20 | ```bash 21 | pip install tox 22 | ``` 23 | 24 | Run it: 25 | 26 | ```bash 27 | tox 28 | ``` 29 | 30 | The tests are in `test_pyo3_mixed.py`, while the configuration is in tox.ini 31 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | import os.path 4 | import platform 5 | import sys 6 | from pathlib import Path 7 | from subprocess import check_output 8 | 9 | from boltons.strutils import slugify 10 | 11 | import pyo3_mixed 12 | 13 | assert pyo3_mixed.get_42() == 42 14 | assert slugify("First post! Hi!!!!~1 ") == "first_post_hi_1" 15 | 16 | script_name = "print_cli_args" 17 | args = ["a", "b", "c"] 18 | [rust_args, python_args] = check_output([script_name, *args], text=True).splitlines() 19 | # The rust vec debug format is also valid json 20 | rust_args = json.loads(rust_args) 21 | python_args = json.loads(python_args) 22 | 23 | # On alpine/musl, rust_args is empty so we skip all tests on musl 24 | if len(rust_args) > 0: 25 | # On linux we get sys.executable, windows resolve the path and mac os gives us a third 26 | # path ( 27 | # {prefix}/Python.framework/Versions/3.10/Resources/Python.app/Contents/MacOS/Python 28 | # vs 29 | # {prefix}/Python.framework/Versions/3.10/bin/python3.10 30 | # on cirrus ci) 31 | # On windows, cpython resolves while pypy doesn't. 32 | # The script for cpython is actually a distinct file from the system interpreter for 33 | # windows and mac 34 | if platform.system() == "Linux": 35 | assert os.path.samefile(rust_args[0], sys.executable), ( 36 | rust_args, 37 | sys.executable, 38 | os.path.realpath(rust_args[0]), 39 | os.path.realpath(sys.executable), 40 | ) 41 | 42 | # Windows can't decide if it's with or without .exe, FreeBSB just doesn't work for some reason 43 | if platform.system() in ["Darwin", "Linux"]: 44 | # Unix venv layout (and hopefully also on more exotic platforms) 45 | print_cli_args = str(Path(sys.prefix).joinpath("bin").joinpath(script_name)) 46 | assert rust_args[1] == print_cli_args, (rust_args, print_cli_args) 47 | assert python_args[0] == print_cli_args, (python_args, print_cli_args) 48 | 49 | # FreeBSB just doesn't work for some reason 50 | if platform.system() in ["Darwin", "Linux", "Windows"]: 51 | # Rust contains the python executable as first argument but python does not 52 | assert rust_args[2:] == args, rust_args 53 | assert python_args[1:] == args, python_args 54 | 55 | print("SUCCESS") 56 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/pyo3-config.txt: -------------------------------------------------------------------------------- 1 | implementation=CPython 2 | version=3.10 3 | shared=true 4 | abi3=false 5 | suppress_build_script_link_lines=false 6 | pointer_width=64 7 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/pyo3_mixed/__init__.py: -------------------------------------------------------------------------------- 1 | from .pyo3_mixed import get_21, print_cli_args # noqa: F401 2 | from .python_module.double import double 3 | 4 | 5 | def get_42() -> int: 6 | return double(get_21) 7 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/pyo3_mixed/assets/asset.txt: -------------------------------------------------------------------------------- 1 | This file is included twice, once implicitly by in the python root and once explicitly in pyproject.toml 2 | and checks that it gets deduplicated, see https://github.com/PyO3/maturin/issues/2106 and 3 | https://github.com/PyO3/maturin/issues/2066. 4 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/pyo3_mixed/python_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/pyo3-mixed/pyo3_mixed/python_module/__init__.py -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/pyo3_mixed/python_module/double.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | 4 | def double(fn: Callable[[], int]) -> int: 5 | return 2 * fn() 6 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pyo3-mixed" 7 | classifiers = [ 8 | "Programming Language :: Python", 9 | "Programming Language :: Rust" 10 | ] 11 | requires-python = ">=3.7" 12 | dependencies = ["boltons"] 13 | dynamic = ["version"] 14 | 15 | [project.scripts] 16 | get_42 = "pyo3_mixed:get_42" 17 | print_cli_args = "pyo3_mixed:print_cli_args" 18 | 19 | [tool.maturin] 20 | include = ["pyo3_mixed/assets/*"] 21 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | use std::env; 3 | 4 | #[pyfunction] 5 | fn get_21() -> usize { 6 | 21 7 | } 8 | 9 | /// Prints the CLI arguments, once from Rust's point of view and once from Python's point of view. 10 | #[pyfunction] 11 | fn print_cli_args(py: Python) -> PyResult<()> { 12 | // This one includes Python and the name of the wrapper script itself, e.g. 13 | // `["/home/ferris/.venv/bin/python", "/home/ferris/.venv/bin/print_cli_args", "a", "b", "c"]` 14 | println!("{:?}", env::args().collect::>()); 15 | // This one includes only the name of the wrapper script itself, e.g. 16 | // `["/home/ferris/.venv/bin/print_cli_args", "a", "b", "c"])` 17 | println!( 18 | "{:?}", 19 | py.import("sys")? 20 | .getattr("argv")? 21 | .extract::>()? 22 | ); 23 | Ok(()) 24 | } 25 | 26 | #[pymodule] 27 | fn pyo3_mixed(m: &Bound<'_, PyModule>) -> PyResult<()> { 28 | m.add_wrapped(wrap_pyfunction!(get_21))?; 29 | m.add_wrapped(wrap_pyfunction!(print_cli_args))?; 30 | 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/tests/test_pyo3_mixed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_mixed 4 | 5 | 6 | def test_get_42(): 7 | assert pyo3_mixed.get_42() == 42 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-mixed/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest tests/ 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-no-extension-module/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "1.3.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 10 | 11 | [[package]] 12 | name = "cfg-if" 13 | version = "1.0.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 16 | 17 | [[package]] 18 | name = "libc" 19 | version = "0.2.155" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 22 | 23 | [[package]] 24 | name = "memoffset" 25 | version = "0.9.1" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" 28 | dependencies = [ 29 | "autocfg", 30 | ] 31 | 32 | [[package]] 33 | name = "once_cell" 34 | version = "1.19.0" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 37 | 38 | [[package]] 39 | name = "portable-atomic" 40 | version = "1.6.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" 43 | 44 | [[package]] 45 | name = "pyo3" 46 | version = "0.24.1" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "17da310086b068fbdcefbba30aeb3721d5bb9af8db4987d6735b2183ca567229" 49 | dependencies = [ 50 | "cfg-if", 51 | "libc", 52 | "memoffset", 53 | "once_cell", 54 | "portable-atomic", 55 | "pyo3-build-config", 56 | "pyo3-ffi", 57 | ] 58 | 59 | [[package]] 60 | name = "pyo3-build-config" 61 | version = "0.24.1" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "e27165889bd793000a098bb966adc4300c312497ea25cf7a690a9f0ac5aa5fc1" 64 | dependencies = [ 65 | "once_cell", 66 | "target-lexicon", 67 | ] 68 | 69 | [[package]] 70 | name = "pyo3-ffi" 71 | version = "0.24.1" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "05280526e1dbf6b420062f3ef228b78c0c54ba94e157f5cb724a609d0f2faabc" 74 | dependencies = [ 75 | "libc", 76 | "pyo3-build-config", 77 | ] 78 | 79 | [[package]] 80 | name = "pyo3-no-extension-module" 81 | version = "2.1.0" 82 | dependencies = [ 83 | "pyo3", 84 | ] 85 | 86 | [[package]] 87 | name = "target-lexicon" 88 | version = "0.13.2" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" 91 | -------------------------------------------------------------------------------- /test-crates/pyo3-no-extension-module/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["konstin "] 3 | name = "pyo3-no-extension-module" 4 | version = "2.1.0" 5 | description = "Does not use the extension-module feature, thus erroneously linking libpython" 6 | edition = "2021" 7 | 8 | [dependencies] 9 | pyo3 = { version = "0.24.0", default-features = false } 10 | 11 | [lib] 12 | name = "pyo3_no_extension_module" 13 | crate-type = ["cdylib"] 14 | -------------------------------------------------------------------------------- /test-crates/pyo3-no-extension-module/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::ffi::{PyDict_New, PyObject}; 2 | 3 | #[no_mangle] 4 | #[allow(non_snake_case)] 5 | pub unsafe extern "C" fn PyInit_pyo3_pure() -> *mut PyObject { 6 | PyDict_New() // Make sure an ffi function is used 7 | } 8 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["konstin "] 3 | name = "pyo3-pure" 4 | version = "2.1.2" 5 | edition = "2021" 6 | description = "Implements a dummy function (get_fortytwo.DummyClass.get_42()) in rust" 7 | license = "MIT" 8 | 9 | [dependencies] 10 | pyo3 = { version = "0.24.0", features = [ 11 | "abi3-py37", 12 | "extension-module", 13 | "generate-import-lib", 14 | ] } 15 | 16 | [lib] 17 | name = "pyo3_pure" 18 | crate-type = ["cdylib"] 19 | 20 | [workspace] 21 | members = [".", "local-test"] 22 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-present konstin 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/README.md: -------------------------------------------------------------------------------- 1 | # Get fourtytwo 2 | 3 | A package with pyo3 bindings for testing maturin. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | pip install . 9 | ``` 10 | 11 | ```python 12 | import pyo3_pure 13 | assert pyo3_pure.DummyClass.get_42() == 42 14 | ``` 15 | 16 | ## Testing 17 | 18 | Install tox: 19 | 20 | ```bash 21 | pip install tox 22 | ``` 23 | 24 | Run it: 25 | 26 | ```bash 27 | tox 28 | ``` 29 | 30 | The tests are in `test_pyo3_pure.py`, while the configuration is in tox.ini 31 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import subprocess 4 | 5 | import pyo3_pure 6 | 7 | assert pyo3_pure.DummyClass.get_42() == 42 8 | 9 | # Check type stub 10 | install_path = os.path.join(os.path.dirname(pyo3_pure.__file__)) 11 | assert os.path.exists(os.path.join(install_path, "__init__.pyi")) 12 | assert os.path.exists(os.path.join(install_path, "py.typed")) 13 | 14 | # Check entrypoints 15 | assert subprocess.run(["get_42"]).returncode == 42 16 | 17 | print("SUCCESS") 18 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/local-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "local-test" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/local-test/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn add(left: usize, right: usize) -> usize { 2 | left + right 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | 9 | #[test] 10 | fn it_works() { 11 | let result = add(2, 2); 12 | assert_eq!(result, 4); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/pyo3_pure.pyi: -------------------------------------------------------------------------------- 1 | class DummyClass: 2 | @staticmethod 3 | def get_42() -> int: ... 4 | 5 | fourtytwo: int 6 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [tool.maturin] 6 | bindings = "pyo3" 7 | 8 | [tool.maturin.target."x86_64-apple-darwin"] 9 | macos-deployment-target = "10.12" 10 | 11 | [tool.maturin.target."aarch64-apple-darwin"] 12 | macos-deployment-target = "11.0" 13 | 14 | [project] 15 | # The name pyo3_pure instead of pyo3-pure is intentional, 16 | # it's used as a crate name resolution regression test 17 | name = "pyo3_pure" 18 | version = "0.1.0+abc123de" 19 | classifiers = [ 20 | "Programming Language :: Rust" 21 | ] 22 | description = "Implements a dummy function in Rust" 23 | readme = "README.md" 24 | maintainers = [ 25 | {name = "messense", email = "messense@icloud.com"} 26 | ] 27 | license = { file = "LICENSE" } 28 | 29 | [project.optional-dependencies] 30 | test = [ 31 | "attrs", 32 | "boltons; sys_platform == 'win32'" 33 | ] 34 | 35 | [project.scripts] 36 | get_42 = "pyo3_pure:DummyClass.get_42" 37 | 38 | [project.gui-scripts] 39 | get_42_gui = "pyo3_pure:DummyClass.get_42" 40 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pyclass] 4 | struct DummyClass {} 5 | 6 | #[pymethods] 7 | impl DummyClass { 8 | #[staticmethod] 9 | fn get_42() -> PyResult { 10 | Ok(42) 11 | } 12 | } 13 | 14 | /// module level doc string 15 | #[pymodule] 16 | fn pyo3_pure(m: &Bound<'_, PyModule>) -> PyResult<()> { 17 | m.add_class::()?; 18 | m.add("fourtytwo", 42)?; 19 | 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/tests/test_pyo3_pure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pyo3_pure 4 | 5 | import pytest 6 | 7 | 8 | def test_static(): 9 | assert pyo3_pure.fourtytwo == 42 10 | 11 | 12 | def test_class(): 13 | assert pyo3_pure.DummyClass.get_42() == 42 14 | 15 | 16 | def test_function(): 17 | with pytest.raises(AssertionError): 18 | assert pyo3_pure.DummyClass == 42 19 | -------------------------------------------------------------------------------- /test-crates/pyo3-pure/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36,py37,py38 3 | isolated_build = True 4 | 5 | [testenv] 6 | deps = pytest 7 | commands = pytest tests/ 8 | -------------------------------------------------------------------------------- /test-crates/readme-duplication/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["readme-py", "readme-rs"] 4 | 5 | [workspace.package] 6 | readme = "README.md" 7 | -------------------------------------------------------------------------------- /test-crates/readme-duplication/README.md: -------------------------------------------------------------------------------- 1 | Readme duplication test case - Readme 1 2 | -------------------------------------------------------------------------------- /test-crates/readme-duplication/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import readme 3 | 4 | assert readme.value == 1 5 | 6 | print("SUCCESS") 7 | -------------------------------------------------------------------------------- /test-crates/readme-duplication/readme-py/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "readme_py" 3 | version = "0.2.0" 4 | edition = "2021" 5 | readme = "README.md" 6 | publish = false 7 | 8 | [lib] 9 | name = "readme" 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | readme-rs = { path = "../readme-rs" } 14 | pyo3 = "0.24.1" 15 | -------------------------------------------------------------------------------- /test-crates/readme-duplication/readme-py/README.md: -------------------------------------------------------------------------------- 1 | Readme duplication test case - Readme 2 2 | -------------------------------------------------------------------------------- /test-crates/readme-duplication/readme-py/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin==1.6.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "readme-py" 7 | version = "0.2.0" 8 | 9 | [tool.maturin] 10 | features = ["pyo3/extension-module"] 11 | -------------------------------------------------------------------------------- /test-crates/readme-duplication/readme-py/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::{pymodule, Bound, PyResult}; 2 | use pyo3::types::{PyModule, PyModuleMethods}; 3 | 4 | #[pymodule] 5 | fn readme(m: &Bound) -> PyResult<()> { 6 | m.add("value", 1)?; 7 | Ok(()) 8 | } 9 | -------------------------------------------------------------------------------- /test-crates/readme-duplication/readme-rs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "readme-rs" 3 | version = "0.2.0" 4 | edition = "2021" 5 | readme.workspace = true 6 | -------------------------------------------------------------------------------- /test-crates/readme-duplication/readme-rs/src/lib.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/readme-duplication/readme-rs/src/lib.rs -------------------------------------------------------------------------------- /test-crates/sdist_with_path_dep/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdist_with_path_dep" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | pyo3 = { version = "0.24.0", features = ["extension-module"] } 12 | some_path_dep = { path = "../some_path_dep" } 13 | -------------------------------------------------------------------------------- /test-crates/sdist_with_path_dep/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/sdist_with_path_dep/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pyfunction] 4 | fn add(x: usize, y: usize) -> usize { 5 | let sum = some_path_dep::add(x, y); 6 | debug_assert!(some_path_dep::is_sum(x, y, sum)); 7 | sum 8 | } 9 | 10 | #[pymodule] 11 | fn sdist_with_path_dep(m: &Bound<'_, PyModule>) -> PyResult<()> { 12 | m.add_wrapped(wrap_pyfunction!(add))?; 13 | Ok(()) 14 | } 15 | -------------------------------------------------------------------------------- /test-crates/sdist_with_target_path_dep/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdist_with_target_path_dep" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | pyo3 = { version = "0.24.0", features = ["extension-module"] } 12 | 13 | [target.'cfg(not(target_endian = "all-over-the-place"))'.dependencies] 14 | some_path_dep = { path = "../some_path_dep" } 15 | -------------------------------------------------------------------------------- /test-crates/sdist_with_target_path_dep/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/sdist_with_target_path_dep/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pyfunction] 4 | fn add(x: usize, y: usize) -> usize { 5 | let sum = some_path_dep::add(x, y); 6 | debug_assert!(some_path_dep::is_sum(x, y, sum)); 7 | sum 8 | } 9 | 10 | #[pymodule] 11 | fn sdist_with_target_path_dep(m: &Bound<'_, PyModule>) -> PyResult<()> { 12 | m.add_wrapped(wrap_pyfunction!(add))?; 13 | Ok(()) 14 | } 15 | -------------------------------------------------------------------------------- /test-crates/some_path_dep/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "some_path_dep" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | transitive_path_dep = { path = "../transitive_path_dep" } 11 | -------------------------------------------------------------------------------- /test-crates/some_path_dep/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use transitive_path_dep::is_sum; 2 | 3 | pub fn add(x: usize, y: usize) -> usize { 4 | x + y 5 | } 6 | 7 | #[cfg(test)] 8 | mod tests { 9 | #[test] 10 | fn it_works() { 11 | assert_eq!(add(2, 2), 4); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test-crates/transitive_path_dep/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "transitive_path_dep" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /test-crates/transitive_path_dep/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn is_sum(x: usize, y: usize, sum: usize) -> bool { 2 | x + y == sum 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | #[test] 8 | fn it_works() { 9 | assert_eq!(2 + 2, 4); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test-crates/uniffi-mixed/.gitignore: -------------------------------------------------------------------------------- 1 | uniffi_mixed/uniffi_mixed 2 | -------------------------------------------------------------------------------- /test-crates/uniffi-mixed/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uniffi-mixed" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [lib] 9 | name = "uniffi_mixed" 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | uniffi = "0.28.0" 14 | 15 | [build-dependencies] 16 | uniffi = { version = "0.28.0", features = ["build"] } 17 | -------------------------------------------------------------------------------- /test-crates/uniffi-mixed/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | uniffi::generate_scaffolding("./src/math.udl").unwrap(); 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/uniffi-mixed/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import uniffi_mixed 4 | 5 | assert uniffi_mixed.add(1, 2) == 3 6 | 7 | print("SUCCESS") 8 | -------------------------------------------------------------------------------- /test-crates/uniffi-mixed/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/uniffi-mixed/src/lib.rs: -------------------------------------------------------------------------------- 1 | fn add(a: u32, b: u32) -> u32 { 2 | a + b 3 | } 4 | 5 | uniffi::include_scaffolding!("math"); 6 | -------------------------------------------------------------------------------- /test-crates/uniffi-mixed/src/math.udl: -------------------------------------------------------------------------------- 1 | namespace math { 2 | u32 add(u32 a, u32 b); 3 | }; 4 | -------------------------------------------------------------------------------- /test-crates/uniffi-mixed/test_uniffi_mixed.py: -------------------------------------------------------------------------------- 1 | import uniffi_mixed 2 | 3 | 4 | def test_add(): 5 | assert uniffi_mixed.add(1, 2) == 3 6 | -------------------------------------------------------------------------------- /test-crates/uniffi-mixed/uniffi_mixed/__init__.py: -------------------------------------------------------------------------------- 1 | from .uniffi_mixed import * # NOQA 2 | -------------------------------------------------------------------------------- /test-crates/uniffi-multiple-binding-files/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uniffi-multiple-binding-files" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [lib] 9 | name = "uniffi_multiple_binding_files" 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | uniffi = { version = "0.28.0", features = ["cli"] } 14 | mylib = { path = "mylib" } 15 | 16 | [build-dependencies] 17 | uniffi = { version = "0.28.0", features = ["build"] } 18 | -------------------------------------------------------------------------------- /test-crates/uniffi-multiple-binding-files/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import uniffi_multiple_binding_files 4 | 5 | assert uniffi_multiple_binding_files.get_status() == uniffi_multiple_binding_files.mylib.Status.COMPLETE 6 | 7 | print("SUCCESS") 8 | -------------------------------------------------------------------------------- /test-crates/uniffi-multiple-binding-files/mylib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mylib" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | uniffi = { version = "0.28.0" } 10 | -------------------------------------------------------------------------------- /test-crates/uniffi-multiple-binding-files/mylib/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[derive(uniffi::Enum)] 2 | pub enum Status { 3 | Running, 4 | Complete, 5 | } 6 | 7 | pub fn get_status() -> Status { 8 | Status::Complete 9 | } 10 | 11 | uniffi::setup_scaffolding!(); 12 | -------------------------------------------------------------------------------- /test-crates/uniffi-multiple-binding-files/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[uniffi::export] 2 | pub fn get_status() -> mylib::Status { 3 | mylib::get_status() 4 | } 5 | 6 | uniffi::setup_scaffolding!(); 7 | -------------------------------------------------------------------------------- /test-crates/uniffi-multiple-binding-files/uniffi.toml: -------------------------------------------------------------------------------- 1 | [bindings.python] 2 | cdylib_name = "uniffi_multiple_binding_files" 3 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure-proc-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uniffi-pure-proc-macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [lib] 9 | name = "uniffi_pure_proc_macro" 10 | crate-type = ["cdylib"] 11 | 12 | [[bin]] 13 | name = "uniffi-bindgen" 14 | path = "uniffi-bindgen.rs" 15 | 16 | [dependencies] 17 | uniffi = { version = "0.28.0", features = ["cli"] } 18 | 19 | [build-dependencies] 20 | uniffi = { version = "0.28.0", features = ["build"] } 21 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure-proc-macro/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import uniffi_pure_proc_macro as uniffi_pure 4 | 5 | assert uniffi_pure.add(1, 2) == 3 6 | 7 | print("SUCCESS") 8 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure-proc-macro/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure-proc-macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[uniffi::export] 2 | fn add(a: u32, b: u32) -> u32 { 3 | a + b 4 | } 5 | 6 | uniffi::setup_scaffolding!(); 7 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure-proc-macro/test_uniffi_pure.py: -------------------------------------------------------------------------------- 1 | import uniffi_pure_proc_macro as uniffi_pure 2 | 3 | 4 | def test_add(): 5 | assert uniffi_pure.add(1, 2) == 3 6 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure-proc-macro/uniffi-bindgen.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | uniffi::uniffi_bindgen_main() 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure-proc-macro/uniffi.toml: -------------------------------------------------------------------------------- 1 | [bindings.python] 2 | cdylib_name = "example" 3 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uniffi-pure" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [lib] 9 | name = "uniffi_pure" 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | uniffi = "0.28.0" 14 | 15 | [build-dependencies] 16 | uniffi = { version = "0.28.0", features = ["build"] } 17 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | uniffi::generate_scaffolding("./src/math.udl").unwrap(); 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import uniffi_pure 4 | 5 | assert uniffi_pure.add(1, 2) == 3 6 | 7 | print("SUCCESS") 8 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure/src/lib.rs: -------------------------------------------------------------------------------- 1 | fn add(a: u32, b: u32) -> u32 { 2 | a + b 3 | } 4 | 5 | uniffi::include_scaffolding!("math"); 6 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure/src/math.udl: -------------------------------------------------------------------------------- 1 | namespace math { 2 | u32 add(u32 a, u32 b); 3 | }; 4 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure/test_uniffi_pure.py: -------------------------------------------------------------------------------- 1 | import uniffi_pure 2 | 3 | 4 | def test_add(): 5 | assert uniffi_pure.add(1, 2) == 3 6 | -------------------------------------------------------------------------------- /test-crates/uniffi-pure/uniffi.toml: -------------------------------------------------------------------------------- 1 | [bindings.python] 2 | cdylib_name = "example" 3 | -------------------------------------------------------------------------------- /test-crates/update_readme.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import re 3 | import subprocess 4 | from pathlib import Path 5 | 6 | 7 | FILES = [ 8 | "README.md", 9 | "guide/src/local_development.md", 10 | "guide/src/tutorial.md", 11 | "guide/src/distribution.md", 12 | ] 13 | 14 | 15 | def main(): 16 | root = Path(subprocess.check_output(["git", "rev-parse", "--show-toplevel"], text=True).strip()) 17 | 18 | for path in FILES: 19 | content = root.joinpath(path).read_text() 20 | 21 | matcher = re.compile(r"```\nUsage: maturin (\w+) (.*?)```", re.MULTILINE | re.DOTALL) 22 | 23 | replaces = {} 24 | for command, old in matcher.findall(content): 25 | command_output = subprocess.check_output(["cargo", "run", "--", command.lower(), "--help"], text=True) 26 | new = "Usage:" + command_output.strip().split("Usage:")[1] + "\n" 27 | # Remove trailing whitespace 28 | new = re.sub(" +\n", "\n", new) 29 | old = "Usage: maturin " + command + " " + old 30 | replaces[old] = new 31 | 32 | for old, new in replaces.items(): 33 | content = content.replace(old, new) 34 | root.joinpath(path).write_text(content) 35 | 36 | 37 | if __name__ == "__main__": 38 | main() 39 | -------------------------------------------------------------------------------- /test-crates/with-data/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "with-data" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /test-crates/with-data/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "with-data" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | 7 | [lib] 8 | name = "with_data" 9 | crate-type = ["cdylib"] 10 | -------------------------------------------------------------------------------- /test-crates/with-data/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | import locale 2 | import sys 3 | from pathlib import Path 4 | 5 | import with_data 6 | 7 | assert with_data.lib.one() == 1 8 | assert with_data.ffi.string(with_data.lib.say_hello()).decode() == "hello" 9 | 10 | venv_root = Path(sys.prefix) 11 | 12 | installed_data = ( 13 | venv_root.joinpath("data_subdir") 14 | .joinpath("hello.txt") 15 | # With the default encoding, python under windows fails to read the file correctly 16 | .read_text(encoding="utf-8") 17 | .strip() 18 | ) 19 | assert installed_data == "Hi! 😊", ( 20 | installed_data, 21 | "Hi! 😊", 22 | locale.getpreferredencoding(), 23 | ) 24 | header_file = ( 25 | venv_root.joinpath("include") 26 | .joinpath("site") 27 | .joinpath(f"python{sys.version_info.major}.{sys.version_info.minor}") 28 | .joinpath("with-data") 29 | .joinpath("empty.h") 30 | ) 31 | assert header_file.is_file(), header_file 32 | 33 | print("SUCCESS") 34 | -------------------------------------------------------------------------------- /test-crates/with-data/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "with-data" 7 | dependencies = ["cffi"] 8 | dynamic = ["version"] 9 | -------------------------------------------------------------------------------- /test-crates/with-data/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::CString; 2 | use std::os::raw::{c_char, c_int}; 3 | 4 | #[no_mangle] 5 | pub unsafe extern "C" fn say_hello() -> *const c_char { 6 | CString::new("hello").unwrap().into_raw() 7 | } 8 | 9 | #[no_mangle] 10 | pub unsafe extern "C" fn one() -> c_int { 11 | 1 12 | } 13 | -------------------------------------------------------------------------------- /test-crates/with-data/with_data.data/data/data_subdir/hello.txt: -------------------------------------------------------------------------------- 1 | Hi! 😊 2 | -------------------------------------------------------------------------------- /test-crates/with-data/with_data.data/headers/empty.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/with-data/with_data.data/headers/empty.h -------------------------------------------------------------------------------- /test-crates/workspace-inheritance/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "generic_lib", 4 | "python" 5 | ] 6 | 7 | [workspace.package] 8 | version = "0.1.0" 9 | 10 | [workspace.dependencies] 11 | cfg-if = "1.0.0" 12 | libc = { version = "0.2", features = ["std"] } 13 | rand = "0.8" 14 | generic_lib = { path = "generic_lib" } 15 | -------------------------------------------------------------------------------- /test-crates/workspace-inheritance/generic_lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "generic_lib" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /test-crates/workspace-inheritance/generic_lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn foo() -> &'static str { 2 | "foo" 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/workspace-inheritance/python/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "workspace-inheritance" 3 | version.workspace = true 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [lib] 8 | name = "workspace_inheritance" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pyo3 = { version = "0.24.0", features = ["extension-module"] } 13 | generic_lib.workspace = true 14 | 15 | [dependencies.libc] 16 | workspace = true 17 | optional = true 18 | features = ["extra_traits"] 19 | 20 | [build-dependencies] 21 | cfg-if.workspace = true 22 | 23 | [dev-dependencies] 24 | cfg-if.workspace = true 25 | 26 | [dependencies.cfg-if] 27 | workspace = true 28 | optional = true 29 | 30 | [dependencies.rand] 31 | workspace = true 32 | features = ["small_rng"] 33 | -------------------------------------------------------------------------------- /test-crates/workspace-inheritance/python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=0.15,<0.16"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/workspace-inheritance/python/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | /// Formats the sum of two numbers as string. 4 | #[pyfunction] 5 | fn sum_as_string(a: usize, b: usize) -> PyResult { 6 | Ok((a + b).to_string()) 7 | } 8 | 9 | /// A Python module implemented in Rust. 10 | #[pymodule] 11 | fn workspace_with_path_dep(m: &Bound<'_, PyModule>) -> PyResult<()> { 12 | m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; 13 | Ok(()) 14 | } 15 | -------------------------------------------------------------------------------- /test-crates/workspace-inverted-order/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | ".", 4 | "path-dep-with-root", 5 | ] 6 | 7 | [workspace.package] 8 | authors = [] 9 | version = "0.10.2-dev" 10 | publish = false 11 | repository = "https://github.com/mitmproxy/mitmproxy-rs" 12 | 13 | [package] 14 | name = "top_level" 15 | version = "0.1.0" 16 | description = "root dep" 17 | edition = "2021" 18 | -------------------------------------------------------------------------------- /test-crates/workspace-inverted-order/README.md: -------------------------------------------------------------------------------- 1 | # Root readme 2 | 3 | In this workspace, the build root is in a subdirectory, while the workspace root also contains a crate. 4 | -------------------------------------------------------------------------------- /test-crates/workspace-inverted-order/check_installed/check_installed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import path_dep_with_root 3 | 4 | assert path_dep_with_root.add_number(2) == 44 5 | 6 | print("SUCCESS") 7 | -------------------------------------------------------------------------------- /test-crates/workspace-inverted-order/path-dep-with-root/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "path_dep_with_root" 3 | version = "0.1.0" 4 | description = "path dep" 5 | edition = "2021" 6 | 7 | [lib] 8 | name = "path_dep_with_root" 9 | crate-type = ["lib", "cdylib"] 10 | 11 | [dependencies] 12 | top_level = { path = "../" } 13 | pyo3 = { version = "0.24.0", features = [ 14 | "abi3", 15 | "abi3-py38", 16 | "extension-module", 17 | ] } 18 | -------------------------------------------------------------------------------- /test-crates/workspace-inverted-order/path-dep-with-root/README.md: -------------------------------------------------------------------------------- 1 | # Path readme 2 | -------------------------------------------------------------------------------- /test-crates/workspace-inverted-order/path-dep-with-root/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1,<2"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "mitmproxy_path" 7 | version = "0.1.0" 8 | requires-python = ">=3.8" 9 | -------------------------------------------------------------------------------- /test-crates/workspace-inverted-order/path-dep-with-root/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | #[pymodule] 4 | mod path_dep_with_root { 5 | use pyo3::pyfunction; 6 | use top_level::NUMBER; 7 | 8 | #[pyfunction] 9 | fn add_number(x: u32) -> u32 { 10 | x + NUMBER 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test-crates/workspace-inverted-order/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.dummy] 2 | value = 1 3 | -------------------------------------------------------------------------------- /test-crates/workspace-inverted-order/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub const NUMBER: u32 = 42; 2 | -------------------------------------------------------------------------------- /test-crates/workspace/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "py" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /test-crates/workspace/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "py" 4 | ] 5 | -------------------------------------------------------------------------------- /test-crates/workspace/Readme.md: -------------------------------------------------------------------------------- 1 | This tests that we ignore non-existent Cargo.lock file listed by `cargo package --list`, which seems to only occur with workspaces. See https://github.com/rust-lang/cargo/issues/7938#issuecomment-593280660 and https://github.com/PyO3/maturin/issues/449 2 | -------------------------------------------------------------------------------- /test-crates/workspace/py/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "py" 3 | version = "0.1.0" 4 | authors = ["konstin "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /test-crates/workspace/py/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=0.15,<0.16"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/workspace/py/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "generic_lib", 4 | "transitive_lib", 5 | "dont_include_in_sdist", 6 | "python" 7 | ] 8 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/dont_include_in_sdist/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dont_include_in_sdist" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/dont_include_in_sdist/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/generic_lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "generic_lib" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | transitive_lib = { path = "../transitive_lib" } 10 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/generic_lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn foo() -> &'static str { 2 | "foo" 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/python/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "workspace_with_path_dep" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | pyo3 = { version = "0.24.1", features = ["extension-module"] } 12 | generic_lib = { path = "../generic_lib" } 13 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/python/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | /// Formats the sum of two numbers as string. 4 | #[pyfunction] 5 | fn sum_as_string(a: usize, b: usize) -> PyResult { 6 | Ok((a + b).to_string()) 7 | } 8 | 9 | /// A Python module implemented in Rust. 10 | #[pymodule] 11 | fn workspace_with_path_dep(m: &Bound<'_, PyModule>) -> PyResult<()> { 12 | m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; 13 | Ok(()) 14 | } 15 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/transitive_lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "transitive_lib" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /test-crates/workspace_with_path_dep/transitive_lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn bar() -> &'static str { 2 | "bar" 3 | } 4 | -------------------------------------------------------------------------------- /test-crates/wrong-python-source/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "wrong-python-source" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /test-crates/wrong-python-source/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrong-python-source" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [[bin]] 7 | name = "run_this" 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /test-crates/wrong-python-source/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.maturin] 2 | bindings = "bin" 3 | python-source = "python" 4 | 5 | [build-system] 6 | requires = ["maturin>=1.0,<2.0"] 7 | build-backend = "maturin" 8 | -------------------------------------------------------------------------------- /test-crates/wrong-python-source/python/run_this/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/wrong-python-source/python/run_this/__init__.py -------------------------------------------------------------------------------- /test-crates/wrong-python-source/src/bin/run_this.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | -------------------------------------------------------------------------------- /test-crates/wrong-python-source/src/lib.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-crates/wrong-python-source/src/lib.rs -------------------------------------------------------------------------------- /test-data/Readme.md: -------------------------------------------------------------------------------- 1 | * `py.exe`: Mock for the windows python launcher we can insert in path 2 | -------------------------------------------------------------------------------- /test-data/py.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/test-data/py.exe -------------------------------------------------------------------------------- /test-dockerfile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Builds all 6 test crates using the docker container, 3 | # installs the wheel and checks that the installed package is functional 4 | 5 | set -e 6 | 7 | rm -rf venv-docker 8 | python3.11 -m venv venv-docker 9 | venv-docker/bin/pip install -U pip cffi 10 | 11 | # FIXME: Can we run the tests without activate? Currently hello-world fails because then the binary is not in PATH 12 | source venv-docker/bin/activate 13 | 14 | for test_crate in hello-world cffi-pure cffi-mixed pyo3-pure pyo3-mixed pyo3-mixed-submodule pyo3-mixed-implicit 15 | do 16 | echo "Testing $test_crate" 17 | docker run -e RUST_BACKTRACE=1 --rm -v "$(pwd):/io" -w /io/test-crates/$test_crate maturin build -i python3.11 18 | # --only-binary=:all: stops pip from picking a local already compiled sdist 19 | venv-docker/bin/pip install $test_crate --only-binary=:all: --find-links test-crates/$test_crate/target/wheels/ 20 | if [[ $(venv-docker/bin/python test-crates/$test_crate/check_installed/check_installed.py) != 'SUCCESS' ]]; then 21 | exit 1 22 | fi 23 | done 24 | 25 | deactivate 26 | -------------------------------------------------------------------------------- /tests/cli.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn cli_tests() { 3 | let t = trycmd::TestCases::new(); 4 | t.default_bin_name("maturin"); 5 | t.case("tests/cmd/*.toml"); 6 | 7 | #[cfg(not(feature = "upload"))] 8 | { 9 | t.skip("tests/cmd/upload.toml"); 10 | t.skip("tests/cmd/publish.toml"); 11 | } 12 | 13 | #[cfg(not(feature = "zig"))] 14 | { 15 | t.skip("tests/cmd/build.toml"); 16 | } 17 | 18 | #[cfg(not(feature = "scaffolding"))] 19 | { 20 | t.skip("tests/cmd/new.toml"); 21 | t.skip("tests/cmd/init.toml"); 22 | t.skip("tests/cmd/generate-ci.toml"); 23 | } 24 | 25 | #[cfg(not(all(feature = "upload", feature = "zig", feature = "scaffolding")))] 26 | { 27 | t.skip("tests/cmd/maturin.toml"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/cmd/build.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/build.stderr -------------------------------------------------------------------------------- /tests/cmd/build.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "build --help" 3 | -------------------------------------------------------------------------------- /tests/cmd/develop.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/develop.stderr -------------------------------------------------------------------------------- /tests/cmd/develop.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "develop --help" 3 | -------------------------------------------------------------------------------- /tests/cmd/generate-ci.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/generate-ci.stderr -------------------------------------------------------------------------------- /tests/cmd/generate-ci.stdout: -------------------------------------------------------------------------------- 1 | Generate CI configuration 2 | 3 | Usage: maturin[EXE] generate-ci [OPTIONS] 4 | 5 | Arguments: 6 | 7 | CI provider 8 | 9 | Possible values: 10 | - github: GitHub 11 | 12 | Options: 13 | -m, --manifest-path 14 | Path to Cargo.toml 15 | 16 | -v, --verbose... 17 | Use verbose output. 18 | 19 | * Default: Show build information and `cargo build` output. * `-v`: Use `cargo build -v`. 20 | * `-vv`: Show debug logging and use `cargo build -vv`. * `-vvv`: Show trace logging. 21 | 22 | You can configure fine-grained logging using the `RUST_LOG` environment variable. 23 | () 24 | 25 | -o, --output 26 | Output path 27 | 28 | [default: -] 29 | 30 | --platform ... 31 | Platform support 32 | 33 | [default: linux musllinux windows macos] 34 | 35 | Possible values: 36 | - all: All 37 | - manylinux: Manylinux 38 | - musllinux: Musllinux 39 | - windows: Windows 40 | - macos: macOS 41 | - emscripten: Emscripten 42 | 43 | --pytest 44 | Enable pytest 45 | 46 | --zig 47 | Use zig to do cross compilation 48 | 49 | --skip-attestation 50 | Skip artifact attestation 51 | 52 | -h, --help 53 | Print help (see a summary with '-h') 54 | -------------------------------------------------------------------------------- /tests/cmd/generate-ci.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "generate-ci --help" 3 | -------------------------------------------------------------------------------- /tests/cmd/init.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/init.stderr -------------------------------------------------------------------------------- /tests/cmd/init.stdout: -------------------------------------------------------------------------------- 1 | Create a new cargo project in an existing directory 2 | 3 | Usage: maturin[EXE] init [OPTIONS] [PATH] 4 | 5 | Arguments: 6 | [PATH] 7 | Project path 8 | 9 | Options: 10 | --name 11 | Set the resulting package name, defaults to the directory name 12 | 13 | -v, --verbose... 14 | Use verbose output. 15 | 16 | * Default: Show build information and `cargo build` output. * `-v`: Use `cargo build -v`. 17 | * `-vv`: Show debug logging and use `cargo build -vv`. * `-vvv`: Show trace logging. 18 | 19 | You can configure fine-grained logging using the `RUST_LOG` environment variable. 20 | () 21 | 22 | --mixed 23 | Use mixed Rust/Python project layout 24 | 25 | --src 26 | Use Python first src layout for mixed Rust/Python project 27 | 28 | -b, --bindings 29 | Which kind of bindings to use 30 | 31 | [possible values: pyo3, cffi, uniffi, bin] 32 | 33 | -h, --help 34 | Print help (see a summary with '-h') 35 | -------------------------------------------------------------------------------- /tests/cmd/init.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "init --help" 3 | -------------------------------------------------------------------------------- /tests/cmd/list-python.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/list-python.stderr -------------------------------------------------------------------------------- /tests/cmd/list-python.stdout: -------------------------------------------------------------------------------- 1 | Search and list the available python installations 2 | 3 | Usage: maturin[EXE] list-python [OPTIONS] 4 | 5 | Options: 6 | --target 7 | 8 | 9 | -v, --verbose... 10 | Use verbose output. 11 | 12 | * Default: Show build information and `cargo build` output. * `-v`: Use `cargo build -v`. 13 | * `-vv`: Show debug logging and use `cargo build -vv`. * `-vvv`: Show trace logging. 14 | 15 | You can configure fine-grained logging using the `RUST_LOG` environment variable. 16 | () 17 | 18 | -h, --help 19 | Print help (see a summary with '-h') 20 | -------------------------------------------------------------------------------- /tests/cmd/list-python.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "list-python --help" 3 | -------------------------------------------------------------------------------- /tests/cmd/maturin.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/maturin.stderr -------------------------------------------------------------------------------- /tests/cmd/maturin.stdout: -------------------------------------------------------------------------------- 1 | Build and publish crates with pyo3, cffi and uniffi bindings as well as rust binaries as python 2 | packages 3 | 4 | Usage: maturin[EXE] [OPTIONS] 5 | 6 | Commands: 7 | build Build the crate into python packages 8 | publish Build and publish the crate as python packages to pypi 9 | list-python Search and list the available python installations 10 | develop Install the crate as module in the current virtualenv 11 | sdist Build only a source distribution (sdist) without compiling 12 | init Create a new cargo project in an existing directory 13 | new Create a new cargo project 14 | generate-ci Generate CI configuration 15 | upload Upload python packages to pypi 16 | help Print this message or the help of the given subcommand(s) 17 | 18 | Options: 19 | -v, --verbose... 20 | Use verbose output. 21 | 22 | * Default: Show build information and `cargo build` output. * `-v`: Use `cargo build -v`. 23 | * `-vv`: Show debug logging and use `cargo build -vv`. * `-vvv`: Show trace logging. 24 | 25 | You can configure fine-grained logging using the `RUST_LOG` environment variable. 26 | () 27 | 28 | -h, --help 29 | Print help (see a summary with '-h') 30 | 31 | -V, --version 32 | Print version 33 | 34 | Visit https://maturin.rs to learn more about maturin. 35 | -------------------------------------------------------------------------------- /tests/cmd/maturin.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "--help" 3 | -------------------------------------------------------------------------------- /tests/cmd/new.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/new.stderr -------------------------------------------------------------------------------- /tests/cmd/new.stdout: -------------------------------------------------------------------------------- 1 | Create a new cargo project 2 | 3 | Usage: maturin[EXE] new [OPTIONS] 4 | 5 | Arguments: 6 | 7 | Project path 8 | 9 | Options: 10 | --name 11 | Set the resulting package name, defaults to the directory name 12 | 13 | -v, --verbose... 14 | Use verbose output. 15 | 16 | * Default: Show build information and `cargo build` output. * `-v`: Use `cargo build -v`. 17 | * `-vv`: Show debug logging and use `cargo build -vv`. * `-vvv`: Show trace logging. 18 | 19 | You can configure fine-grained logging using the `RUST_LOG` environment variable. 20 | () 21 | 22 | --mixed 23 | Use mixed Rust/Python project layout 24 | 25 | --src 26 | Use Python first src layout for mixed Rust/Python project 27 | 28 | -b, --bindings 29 | Which kind of bindings to use 30 | 31 | [possible values: pyo3, cffi, uniffi, bin] 32 | 33 | -h, --help 34 | Print help (see a summary with '-h') 35 | -------------------------------------------------------------------------------- /tests/cmd/new.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "new --help" 3 | -------------------------------------------------------------------------------- /tests/cmd/publish.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/publish.stderr -------------------------------------------------------------------------------- /tests/cmd/publish.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "publish --help" 3 | -------------------------------------------------------------------------------- /tests/cmd/sdist.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/sdist.stderr -------------------------------------------------------------------------------- /tests/cmd/sdist.stdout: -------------------------------------------------------------------------------- 1 | Build only a source distribution (sdist) without compiling. 2 | 3 | Building a source distribution requires a pyproject.toml with a `[build-system]` table. 4 | 5 | This command is a workaround for [pypa/pip#6041](https://github.com/pypa/pip/issues/6041) 6 | 7 | Usage: maturin[EXE] sdist [OPTIONS] 8 | 9 | Options: 10 | -m, --manifest-path 11 | The path to the Cargo.toml 12 | 13 | -v, --verbose... 14 | Use verbose output. 15 | 16 | * Default: Show build information and `cargo build` output. * `-v`: Use `cargo build -v`. 17 | * `-vv`: Show debug logging and use `cargo build -vv`. * `-vvv`: Show trace logging. 18 | 19 | You can configure fine-grained logging using the `RUST_LOG` environment variable. 20 | () 21 | 22 | -o, --out 23 | The directory to store the built wheels in. Defaults to a new "wheels" directory in the 24 | project's target directory 25 | 26 | -h, --help 27 | Print help (see a summary with '-h') 28 | -------------------------------------------------------------------------------- /tests/cmd/sdist.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "sdist --help" 3 | -------------------------------------------------------------------------------- /tests/cmd/upload.stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyO3/maturin/b3e8be3986df7dd8622e0c285082848ab7c0159a/tests/cmd/upload.stderr -------------------------------------------------------------------------------- /tests/cmd/upload.stdout: -------------------------------------------------------------------------------- 1 | Upload python packages to pypi 2 | 3 | It is mostly similar to `twine upload`, but can only upload python wheels and source distributions. 4 | 5 | Usage: maturin[EXE] upload [OPTIONS] [FILE]... 6 | 7 | Arguments: 8 | [FILE]... 9 | The python packages to upload 10 | 11 | Options: 12 | -r, --repository 13 | The repository (package index) to upload the package to. Should be a section in the config 14 | file. 15 | 16 | Can also be set via MATURIN_REPOSITORY environment variable. 17 | 18 | [env: MATURIN_REPOSITORY=] 19 | [default: pypi] 20 | 21 | -v, --verbose... 22 | Use verbose output. 23 | 24 | * Default: Show build information and `cargo build` output. * `-v`: Use `cargo build -v`. 25 | * `-vv`: Show debug logging and use `cargo build -vv`. * `-vvv`: Show trace logging. 26 | 27 | You can configure fine-grained logging using the `RUST_LOG` environment variable. 28 | () 29 | 30 | --repository-url 31 | The URL of the registry where the wheels are uploaded to. This overrides --repository. 32 | 33 | Can also be set via MATURIN_REPOSITORY_URL environment variable. 34 | 35 | [env: MATURIN_REPOSITORY_URL=] 36 | 37 | -u, --username 38 | Username for pypi or your custom registry. 39 | 40 | Can also be set via MATURIN_USERNAME environment variable. 41 | 42 | Set MATURIN_PYPI_TOKEN variable to use token-based authentication instead 43 | 44 | [env: MATURIN_USERNAME=] 45 | 46 | -p, --password 47 | Password for pypi or your custom registry. 48 | 49 | Can also be set via MATURIN_PASSWORD environment variable. 50 | 51 | [env: MATURIN_PASSWORD] 52 | 53 | --skip-existing 54 | Continue uploading files if one already exists. (Only valid when uploading to PyPI. Other 55 | implementations may not support this.) 56 | 57 | --non-interactive 58 | Do not interactively prompt for username/password if the required credentials are missing. 59 | 60 | Can also be set via MATURIN_NON_INTERACTIVE environment variable. 61 | 62 | [env: MATURIN_NON_INTERACTIVE=] 63 | 64 | -h, --help 65 | Print help (see a summary with '-h') 66 | -------------------------------------------------------------------------------- /tests/cmd/upload.toml: -------------------------------------------------------------------------------- 1 | bin.name = "maturin" 2 | args = "upload --help" 3 | -------------------------------------------------------------------------------- /tests/common/develop.rs: -------------------------------------------------------------------------------- 1 | use crate::common::{ 2 | check_installed, create_conda_env, create_virtualenv, maybe_mock_cargo, TestInstallBackend, 3 | }; 4 | use anyhow::Result; 5 | use maturin::{develop, CargoOptions, DevelopOptions}; 6 | use std::path::{Path, PathBuf}; 7 | use std::process::Command; 8 | use std::str; 9 | 10 | /// Creates a virtualenv and activates it, checks that the package isn't installed, uses 11 | /// "maturin develop" to install it and checks it is working 12 | pub fn test_develop( 13 | package: impl AsRef, 14 | bindings: Option, 15 | unique_name: &str, 16 | conda: bool, 17 | test_backend: TestInstallBackend, 18 | ) -> Result<()> { 19 | maybe_mock_cargo(); 20 | 21 | let package = package.as_ref(); 22 | let (venv_dir, python) = if conda { 23 | create_conda_env(&format!("maturin-{unique_name}"), 3, 10)? 24 | } else { 25 | create_virtualenv(unique_name, None)? 26 | }; 27 | 28 | // Ensure the test doesn't wrongly pass 29 | check_installed(package, &python).unwrap_err(); 30 | 31 | let uv = matches!(test_backend, TestInstallBackend::Uv); 32 | let mut pip_packages = Vec::new(); 33 | if unique_name.contains("cffi") { 34 | pip_packages.push("cffi"); 35 | } 36 | if cfg!(any( 37 | target_os = "linux", 38 | target_os = "macos", 39 | target_os = "windows" 40 | )) && uv 41 | { 42 | pip_packages.push("uv"); 43 | } 44 | if !pip_packages.is_empty() { 45 | let mut cmd = Command::new(&python); 46 | cmd.args(["-m", "pip", "install", "--disable-pip-version-check"]) 47 | .args(pip_packages); 48 | let output = cmd.output()?; 49 | if !output.status.success() { 50 | panic!( 51 | "Failed to install cffi: {}\n---stdout:\n{}---stderr:\n{}", 52 | output.status, 53 | str::from_utf8(&output.stdout)?, 54 | str::from_utf8(&output.stderr)? 55 | ); 56 | } 57 | } 58 | 59 | let manifest_file = package.join("Cargo.toml"); 60 | let develop_options = DevelopOptions { 61 | bindings, 62 | release: false, 63 | strip: false, 64 | extras: Vec::new(), 65 | skip_install: false, 66 | pip_path: None, 67 | cargo_options: CargoOptions { 68 | manifest_path: Some(manifest_file), 69 | quiet: true, 70 | target_dir: Some(PathBuf::from(format!("test-crates/targets/{unique_name}"))), 71 | ..Default::default() 72 | }, 73 | uv, 74 | }; 75 | develop(develop_options, &venv_dir)?; 76 | 77 | check_installed(package, &python)?; 78 | Ok(()) 79 | } 80 | -------------------------------------------------------------------------------- /tests/manylinux_compliant.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | for PYBIN in /opt/python/cp3[89]*/bin; do 5 | $1 build -m test-crates/pyo3-mixed/Cargo.toml --target-dir test-crates/targets -i "${PYBIN}/python" --manylinux $2 -o dist 6 | done 7 | -------------------------------------------------------------------------------- /tests/manylinux_incompliant.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Fail because we're running in manylinux2_28, which can't build for manylinux 2010 5 | for PYBIN in /opt/python/cp3[9]*/bin; do 6 | if $1 build -m test-crates/pyo3-mixed/Cargo.toml --target-dir test-crates/targets -i "${PYBIN}/python" --manylinux 2010 -o dist; then 7 | echo "maturin build unexpectedly succeeded" 8 | exit 1 9 | else 10 | echo "maturin build failed as expected" 11 | fi 12 | done 13 | 14 | # Fail because we're linking zlib with black-listed symbols(gzflags), which is not allowed in manylinux 15 | apt-get -v &> /dev/null && apt-get install -y zlib1g-dev || yum install -y zlib-devel 16 | 17 | for PYBIN in /opt/python/cp3[9]*/bin; do 18 | if $1 build -m test-crates/lib_with_disallowed_lib/Cargo.toml --target-dir test-crates/targets -i "${PYBIN}/python" --manylinux 2014 -o dist; then 19 | echo "maturin build unexpectedly succeeded" 20 | exit 1 21 | else 22 | echo "maturin build failed as expected" 23 | fi 24 | done 25 | --------------------------------------------------------------------------------