| # 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. | |
| [build-system] | |
| requires = ["maturin>=1.8.1"] | |
| build-backend = "maturin" | |
| [project] | |
| name = "datafusion" | |
| description = "Build and run queries against data" | |
| readme = "README.md" | |
| license = { file = "LICENSE.txt" } | |
| requires-python = ">=3.10" | |
| keywords = ["dataframe", "datafusion", "query-engine", "rust"] | |
| classifiers = [ | |
| "Development Status :: 2 - Pre-Alpha", | |
| "Intended Audience :: Developers", | |
| "License :: OSI Approved :: Apache Software License", | |
| "License :: OSI Approved", | |
| "Operating System :: MacOS", | |
| "Operating System :: Microsoft :: Windows", | |
| "Operating System :: POSIX :: Linux", | |
| "Programming Language :: Python :: 3", | |
| "Programming Language :: Python :: 3.10", | |
| "Programming Language :: Python :: 3.11", | |
| "Programming Language :: Python :: 3.12", | |
| "Programming Language :: Python :: 3.13", | |
| "Programming Language :: Python :: 3.14", | |
| "Programming Language :: Python :: Free Threading :: 2 - Beta", | |
| "Programming Language :: Python", | |
| "Programming Language :: Rust", | |
| ] | |
| dependencies = [ | |
| # cloudpickle is invoked by the Rust-side PythonLogicalCodec / | |
| # PythonPhysicalCodec via pyo3 to serialize Python UDF callables — | |
| # scalar, aggregate, and window — into the proto wire format. | |
| # Lazy-imported on the encode / decode hot paths (and cached after | |
| # the first import), so users who never serialize a plan or | |
| # expression incur no runtime cost beyond the install footprint. | |
| "cloudpickle>=2.0", | |
| "pyarrow>=16.0.0;python_version<'3.14'", | |
| "pyarrow>=22.0.0;python_version>='3.14'", | |
| "typing-extensions;python_version<'3.13'", | |
| ] | |
| dynamic = ["version"] | |
| [project.urls] | |
| homepage = "https://datafusion.apache.org/python" | |
| documentation = "https://datafusion.apache.org/python" | |
| repository = "https://github.com/apache/datafusion-python" | |
| [tool.isort] | |
| profile = "black" | |
| [tool.maturin] | |
| manifest-path = "crates/core/Cargo.toml" | |
| python-source = "python" | |
| module-name = "datafusion._internal" | |
| include = [{ path = "Cargo.lock", format = "sdist" }] | |
| exclude = [".asf.yaml", ".github/**", "ci/**"] | |
| # Require Cargo.lock is up to date | |
| locked = true | |
| features = ["substrait"] | |
| [tool.pytest.ini_options] | |
| asyncio_mode = "auto" | |
| asyncio_default_fixture_loop_scope = "function" | |
| addopts = "--doctest-modules" | |
| doctest_optionflags = ["NORMALIZE_WHITESPACE", "ELLIPSIS"] | |
| testpaths = ["python/tests", "python/datafusion"] | |
| # Enable docstring linting using the google style guide | |
| [tool.ruff.lint] | |
| select = ["ALL"] | |
| ignore = [ | |
| "A001", # Allow using words like min as variable names | |
| "A002", # Allow using words like filter as variable names | |
| "A005", # Allow module named io | |
| "ANN401", # Allow Any for wrapper classes | |
| "COM812", # Recommended to ignore these rules when using with ruff-format | |
| "FBT001", # Allow boolean positional args | |
| "FBT002", # Allow boolean positional args | |
| "FIX002", # Allow TODO lines - consider removing at some point | |
| "ISC001", # Recommended to ignore these rules when using with ruff-format | |
| "N812", # Allow importing functions as `F` | |
| "PLR0913", # Allow many arguments in function definition | |
| "SLF001", # Allow accessing private members | |
| "TD002", # Do not require author names in TODO statements | |
| "TD003", # Allow TODO lines | |
| ] | |
| [tool.ruff.lint.pydocstyle] | |
| convention = "google" | |
| [tool.ruff.lint.pycodestyle] | |
| max-doc-length = 88 | |
| [tool.ruff.lint.flake8-boolean-trap] | |
| extend-allowed-calls = ["datafusion.lit", "lit"] | |
| # Disable docstring checking for these directories | |
| [tool.ruff.lint.per-file-ignores] | |
| "python/tests/*" = [ | |
| "ANN", | |
| "ARG", | |
| "BLE001", | |
| "D", | |
| "FBT003", | |
| "PD", | |
| "PLC0415", | |
| "PLR0913", | |
| "PLR2004", | |
| "PT004", | |
| "PT011", | |
| "RUF015", | |
| "S101", | |
| "S608", | |
| "SLF", | |
| ] | |
| "examples/*" = [ | |
| "ANN001", | |
| "ANN202", | |
| "D", | |
| "DTZ007", | |
| "E501", | |
| "INP001", | |
| "PLR2004", | |
| "RUF015", | |
| "S101", | |
| "T201", | |
| "W505", | |
| ] | |
| "dev/*" = [ | |
| "ANN001", | |
| "C", | |
| "D", | |
| "E", | |
| "ERA001", | |
| "EXE", | |
| "N817", | |
| "PLR", | |
| "S", | |
| "SIM", | |
| "T", | |
| "UP", | |
| ] | |
| "benchmarks/*" = [ | |
| "ANN001", | |
| "BLE", | |
| "D", | |
| "E", | |
| "ERA001", | |
| "EXE", | |
| "F", | |
| "FURB", | |
| "INP001", | |
| "PLR", | |
| "S", | |
| "SIM", | |
| "T", | |
| "TD", | |
| "TRY", | |
| "UP", | |
| ] | |
| "docs/*" = ["D"] | |
| "docs/source/conf.py" = ["ANN001", "ERA001", "INP001"] | |
| # CI and pre-commit invoke codespell with different paths, so we have a little | |
| # redundancy here, and we intentionally drop python in the path. | |
| [tool.codespell] | |
| skip = [ | |
| "*/tests/test_functions.py", | |
| "*/tests/test_spark_functions.py", | |
| "*/target", | |
| "./uv.lock", | |
| "uv.lock", | |
| "*/tpch/answers_sf1/*", | |
| ] | |
| count = true | |
| ignore-words-list = ["IST", "ans"] | |
| [tool.uv] | |
| # Keep typing-extensions on a single version across all supported Pythons. | |
| # Adding the docs `myst-nb` stack pulled a newer typing-extensions only on | |
| # Python < 3.11, splitting it into two locked versions. Our own | |
| # `typing-extensions; python_full_version < '3.13'` dependency then spanned | |
| # that split, which uv records as an under-specified lock entry that older | |
| # uv versions (such as the one in CI) refuse to parse. Pinning to one | |
| # version removes the fork. | |
| constraint-dependencies = ["typing-extensions>=4.15.0"] | |
| [dependency-groups] | |
| dev = [ | |
| "arro3-core==0.6.5", | |
| "codespell==2.4.1", | |
| "maturin>=1.8.1", | |
| "nanoarrow==0.8.0", | |
| "numpy>1.25.0;python_version<'3.14'", | |
| "numpy>=2.3.2;python_version>='3.14'", | |
| "pre-commit>=4.3.0", | |
| "pyarrow>=19.0.0", | |
| "pytest-asyncio>=0.23.3", | |
| "pytest-timeout>=2.3.1", | |
| "pytest>=7.4.4", | |
| "pyyaml>=6.0.3", | |
| "ruff>=0.15.1", | |
| "toml>=0.10.2", | |
| ] | |
| # Release tooling only. Kept out of `dev` because pygithub pulls in | |
| # cryptography, which ships no free-threaded wheel and fails to build | |
| # from sdist under free-threaded interpreters (PyO3 < 3.14 support). | |
| release = ["pygithub==2.5.0"] | |
| docs = [ | |
| "jinja2>=3.1.5", | |
| # myst-nb supersedes myst-parser: MyST markdown parsing plus executable | |
| # `{code-cell}` notebook directives. Pulls myst-parser, ipykernel, and the | |
| # jupyter execution stack transitively. | |
| "myst-nb>=1.1", | |
| "pandas>=2.0.3", | |
| "pydata-sphinx-theme>=0.16,<0.17", | |
| "setuptools>=75.3.0", | |
| "sphinx-autoapi>=3.4.0", | |
| "sphinx-reredirects>=0.1.5", | |
| "sphinx>=7.1.2", | |
| "sphinx_copybutton>=0.5.2", | |
| ] |