diff --git a/.github/workflows/bindings_python_ci.yml b/.github/workflows/bindings_python_ci.yml new file mode 100644 index 000000000..b51593d10 --- /dev/null +++ b/.github/workflows/bindings_python_ci.yml @@ -0,0 +1,83 @@ +# 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. + +name: Bindings Python CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true + +jobs: + check-rust: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check format + run: cargo fmt --all -- --check + - name: Check clippy + run: cargo clippy --all-targets --all-features -- -D warnings + + check-python: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install tools + run: | + pip install ruff + - name: Check format + working-directory: "bindings/python" + run: | + ruff format . --diff + - name: Check style + working-directory: "bindings/python" + run: | + ruff check . + + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: 3.8 + - uses: PyO3/maturin-action@v1 + with: + working-directory: "bindings/python" + command: build + args: --out dist --sdist + - name: Run tests + working-directory: "bindings/python" + shell: bash + run: | + set -e + pip install dist/pyiceberg_core-*.whl --force-reinstall + pip install pytest + pytest -v diff --git a/.gitignore b/.gitignore index 25b803228..05c11eda6 100644 --- a/.gitignore +++ b/.gitignore @@ -15,9 +15,12 @@ # specific language governing permissions and limitations # under the License. -/target -/Cargo.lock +target +Cargo.lock .idea .vscode **/.DS_Store dist/* +**/venv +*.so +*.pyc diff --git a/Cargo.toml b/Cargo.toml index 70eadf76d..b75454ec4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,11 +18,14 @@ [workspace] resolver = "2" members = [ - "crates/catalog/*", - "crates/examples", - "crates/iceberg", - "crates/integrations/*", - "crates/test_utils", + "crates/catalog/*", + "crates/examples", + "crates/iceberg", + "crates/integrations/*", + "crates/test_utils", +] +exclude = [ + "bindings/python" ] [workspace.package] diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml new file mode 100644 index 000000000..c2c1007b7 --- /dev/null +++ b/bindings/python/Cargo.toml @@ -0,0 +1,35 @@ +# 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. + +[package] +name = "pyiceberg_core_rust" +version = "0.0.1" +edition = "2021" +homepage = "https://rust.iceberg.apache.org" +rust-version = "1.77.1" +# This crate is used to build python bindings, we don't want to publish it +publish = false + +license = "Apache-2.0" +keywords = ["iceberg"] + +[lib] +crate-type = ["cdylib"] + +[dependencies] +iceberg = { path = "../../crates/iceberg" } +pyo3 = { version = "0.22", features = ["extension-module"] } diff --git a/bindings/python/README.md b/bindings/python/README.md new file mode 100644 index 000000000..566a7bcb8 --- /dev/null +++ b/bindings/python/README.md @@ -0,0 +1,44 @@ + + +# Pyiceberg Core + +This project is used to build an iceberg-rust powered core for pyiceberg. + +## Setup + +```shell +python -m venv venv +source ./venv/bin/activate + +pip install maturin +``` + +## Build + +```shell +maturin develop +``` + +## Test + +```shell +maturin develop -E test +pytest -v +``` \ No newline at end of file diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml new file mode 100644 index 000000000..4a489adde --- /dev/null +++ b/bindings/python/pyproject.toml @@ -0,0 +1,43 @@ +# 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.0,<2.0"] +build-backend = "maturin" + +[project] +name = "pyiceberg_core" +version = "0.0.1" +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] + +[project.optional-dependencies] +test = ["pytest"] + +[tool.maturin] +features = ["pyo3/extension-module"] +python-source = "python" +module-name = "pyiceberg_core.pyiceberg_core_rust" + +[tool.ruff.lint] +ignore = ["F403", "F405"] diff --git a/bindings/python/python/pyiceberg_core/__init__.py b/bindings/python/python/pyiceberg_core/__init__.py new file mode 100644 index 000000000..067bb6f07 --- /dev/null +++ b/bindings/python/python/pyiceberg_core/__init__.py @@ -0,0 +1,21 @@ +# 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. + +from .pyiceberg_core_rust import * + +__doc__ = pyiceberg_core_rust.__doc__ +__all__ = pyiceberg_core_rust.__all__ diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs new file mode 100644 index 000000000..f0d5d1935 --- /dev/null +++ b/bindings/python/src/lib.rs @@ -0,0 +1,31 @@ +// 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. + +use iceberg::io::FileIOBuilder; +use pyo3::prelude::*; + +#[pyfunction] +fn hello_world() -> PyResult { + let _ = FileIOBuilder::new_fs_io().build().unwrap(); + Ok("Hello, world!".to_string()) +} + +#[pymodule] +fn pyiceberg_core_rust(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(wrap_pyfunction!(hello_world, m)?)?; + Ok(()) +} diff --git a/bindings/python/tests/test_basic.py b/bindings/python/tests/test_basic.py new file mode 100644 index 000000000..817793ba8 --- /dev/null +++ b/bindings/python/tests/test_basic.py @@ -0,0 +1,22 @@ +# 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. + +from pyiceberg_core import hello_world + + +def test_hello_world(): + hello_world()