blob: 683b27bf2e4a5d82d3148bc52e8ded140b7efb8d [file] [view]
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Introduction
We welcome and encourage contributions of all kinds, such as:
1. Tickets with issue reports of feature requests
2. Documentation improvements
3. Code, both PR and (especially) PR Review.
In addition to submitting new PRs, we have a healthy tradition of community members reviewing each other’s PRs.
Doing so is a great way to help the community as well as get more familiar with Rust and the relevant codebases.
Before opening a pull request that touches PyO3 bindings, please review the
{ref}`PyO3 class mutability guidelines <ffi_pyclass_mutability>` so you can flag missing
`#[pyclass(frozen)]` annotations during development and review.
## How to develop
This assumes that you have rust and cargo installed. We use the workflow recommended by
[pyo3](https://github.com/PyO3/pyo3) and [maturin](https://github.com/PyO3/maturin). We recommend using
[uv](https://docs.astral.sh/uv/) for python package management.
By default `uv` will attempt to build the datafusion python package. For our development we prefer to build manually. This means
that when creating your virtual environment using `uv sync` you need to pass in the additional `--no-install-package datafusion`
and for `uv run` commands the additional parameter `--no-project`
Bootstrap:
```shell
# fetch this repo
git clone git@github.com:apache/datafusion-python.git
# create the virtual environment
uv sync --dev --no-install-package datafusion
# activate the environment
source .venv/bin/activate
```
The tests rely on test data in git submodules.
```shell
git submodule init
git submodule update
```
Whenever rust code changes (your changes or via `git pull`):
```shell
# make sure you activate the venv using "source .venv/bin/activate" first
maturin develop -uv
python -m pytest
```
## Running & Installing pre-commit hooks
arrow-datafusion-python takes advantage of [pre-commit](https://pre-commit.com/) to assist developers with code linting to help reduce the number of commits that ultimately fail in CI due to linter errors. Using the pre-commit hooks is optional for the developer but certainly helpful for keeping PRs clean and concise.
Our pre-commit hooks can be installed by running {code}`pre-commit install`, which will install the configurations in your ARROW_DATAFUSION_PYTHON_ROOT/.github directory and run each time you perform a commit, failing to complete the commit if an offending lint is found allowing you to make changes locally before pushing.
The pre-commit hooks can also be run adhoc without installing them by simply running {code}`pre-commit run --all-files`
## Guidelines for Separating Python and Rust Code
Version 40 of `datafusion-python` introduced `python` wrappers around the `pyo3` generated code to vastly improve the user experience. (See the [blog post](https://datafusion.apache.org/blog/2024/08/20/python-datafusion-40.0.0/) and [pull request](https://github.com/apache/datafusion-python/pull/750) for more details.)
Mostly, the `python` code is limited to pure wrappers with type hints and good docstrings, but there are a few reasons for when the code does more:
1. Trivial aliases like {py:func}`~datafusion.functions.array_append` and {py:func}`~datafusion.functions.list_append`.
2. Simple type conversion, like from a `path` to a `string` of the path or from `number` to `lit(number)`.
3. The additional code makes an API **much** more pythonic, like we do for {py:func}`~datafusion.functions.named_struct` (see [source code](https://github.com/apache/datafusion-python/blob/a0913c728f5f323c1eb4913e614c9d996083e274/python/datafusion/functions.py#L1040-L1046)).
## Update Dependencies
To change test dependencies, change the `pyproject.toml` and run
To update dependencies, run
```shell
uv sync --dev --no-install-package datafusion
```
## Improving Build Speed
The [pyo3](https://github.com/PyO3/pyo3) dependency of this project contains a `build.rs` file which
can cause it to rebuild frequently. You can prevent this from happening by defining a `PYO3_CONFIG_FILE`
environment variable that points to a file with your build configuration. Whenever your build configuration
changes, such as during some major version updates, you will need to regenerate this file. This variable
should point to a fully resolved path on your build machine.
To generate this file, use the following command:
```shell
PYO3_PRINT_CONFIG=1 cargo build
```
This will generate some output that looks like the following. You will want to copy these contents intro
a file. If you place this file in your project directory with filename `.pyo3_build_config` it will
be ignored by `git`.
```
implementation=CPython
version=3.9
shared=true
abi3=true
lib_name=python3.12
lib_dir=/opt/homebrew/opt/python@3.12/Frameworks/Python.framework/Versions/3.12/lib
executable=/Users/myusername/src/datafusion-python/.venv/bin/python
pointer_width=64
build_flags=
suppress_build_script_link_lines=false
```
Add the environment variable to your system.
```shell
export PYO3_CONFIG_FILE="/Users//myusername/src/datafusion-python/.pyo3_build_config"
```
If you are on a Mac and you use VS Code for your IDE, you will want to add these variables
to your settings. You can find the appropriate rust flags by looking in the
`.cargo/config.toml` file.
```
"rust-analyzer.cargo.extraEnv": {
"RUSTFLAGS": "-C link-arg=-undefined -C link-arg=dynamic_lookup",
"PYO3_CONFIG_FILE": "/Users/myusername/src/datafusion-python/.pyo3_build_config"
},
"rust-analyzer.runnables.extraEnv": {
"RUSTFLAGS": "-C link-arg=-undefined -C link-arg=dynamic_lookup",
"PYO3_CONFIG_FILE": "/Users/myusername/src/personal/datafusion-python/.pyo3_build_config"
}
```