From 2b1f63038467be6a1b82a1cc2fb98ae95556aab3 Mon Sep 17 00:00:00 2001 From: John Elizarraras Date: Fri, 27 Sep 2024 10:51:52 -0500 Subject: [PATCH] Migrate project structure to use maturin for rust file import --- .github/workflows/CI.yml | 181 +++++++++++++++++++++++++ .gitignore | 11 ++ Cargo.lock | 171 +++++++++++++++++++++++ Cargo.toml | 12 ++ pyproject.toml | 47 +++++++ pyproject_maturin.toml | 16 +++ {funmap => python/funmap}/__init__.py | 0 {funmap => python/funmap}/cli.py | 7 +- {funmap => python/funmap}/data_urls.py | 0 {funmap => python/funmap}/funmap.py | 0 {funmap => python/funmap}/logger.py | 0 {funmap => python/funmap}/plotting.py | 0 {funmap => python/funmap}/saving.py | 0 {funmap => python/funmap}/utils.py | 0 requirements-dev.lock | 116 ++++++++++++++++ requirements.lock | 115 ++++++++++++++++ src/lib.rs | 14 ++ 17 files changed, 689 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/CI.yml create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 pyproject.toml create mode 100644 pyproject_maturin.toml rename {funmap => python/funmap}/__init__.py (100%) rename {funmap => python/funmap}/cli.py (99%) rename {funmap => python/funmap}/data_urls.py (100%) rename {funmap => python/funmap}/funmap.py (100%) rename {funmap => python/funmap}/logger.py (100%) rename {funmap => python/funmap}/plotting.py (100%) rename {funmap => python/funmap}/saving.py (100%) rename {funmap => python/funmap}/utils.py (100%) create mode 100644 requirements-dev.lock create mode 100644 requirements.lock create mode 100644 src/lib.rs diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 00000000..ad3ec43f --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,181 @@ +# This file is autogenerated by maturin v1.7.4 +# To update, run +# +# maturin generate-ci github +# +name: CI + +on: + push: + branches: + - main + - master + tags: + - '*' + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + linux: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: ubuntu-latest + target: x86_64 + - runner: ubuntu-latest + target: x86 + - runner: ubuntu-latest + target: aarch64 + - runner: ubuntu-latest + target: armv7 + - runner: ubuntu-latest + target: s390x + - runner: ubuntu-latest + target: ppc64le + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + manylinux: auto + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-linux-${{ matrix.platform.target }} + path: dist + + musllinux: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: ubuntu-latest + target: x86_64 + - runner: ubuntu-latest + target: x86 + - runner: ubuntu-latest + target: aarch64 + - runner: ubuntu-latest + target: armv7 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + manylinux: musllinux_1_2 + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-musllinux-${{ matrix.platform.target }} + path: dist + + windows: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: windows-latest + target: x64 + - runner: windows-latest + target: x86 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + architecture: ${{ matrix.platform.target }} + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-windows-${{ matrix.platform.target }} + path: dist + + macos: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: macos-12 + target: x86_64 + - runner: macos-14 + target: aarch64 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-macos-${{ matrix.platform.target }} + path: dist + + sdist: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build sdist + uses: PyO3/maturin-action@v1 + with: + command: sdist + args: --out dist + - name: Upload sdist + uses: actions/upload-artifact@v4 + with: + name: wheels-sdist + path: dist + + release: + name: Release + runs-on: ubuntu-latest + if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} + needs: [linux, musllinux, windows, macos, sdist] + permissions: + # Use to sign the release artifacts + id-token: write + # Used to upload release artifacts + contents: write + # Used to generate artifact attestation + attestations: write + steps: + - uses: actions/download-artifact@v4 + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v1 + with: + subject-path: 'wheels-*/*' + - name: Publish to PyPI + if: "startsWith(github.ref, 'refs/tags/')" + uses: PyO3/maturin-action@v1 + env: + MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + with: + command: upload + args: --non-interactive --skip-existing wheels-*/* diff --git a/.gitignore b/.gitignore index 7ea9ea8f..eba216d4 100644 --- a/.gitignore +++ b/.gitignore @@ -109,3 +109,14 @@ ENV/ .DS_Store results *old + +# python generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# venv +.venv diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..ded191fc --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,171 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "funmap_lib" +version = "0.1.0" +dependencies = [ + "pyo3", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "portable-atomic" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pyo3" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unindent" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..ecac49bc --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "funmap_lib" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "funmap" +crate-type = ["cdylib"] + +[dependencies] +pyo3 = "0.22.0" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..d78d7f95 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,47 @@ +[project] +name = "funmap" +version = "0.2.0" +description = "generate gene co-function networks using omics data" +authors = [{ name = "Zhiao Shi", email = "zhiao.shi@gmail.com" }] +dependencies = [ + "PyPDF2==3.0.1", + "click==8.1.7", + "h5py==3.10.0", + "imbalanced-learn==0.11.0", + "joblib==1.3.2", + "matplotlib==3.7.3", + "matplotlib_venn==0.11.9", + "networkx==3.1", + "numpy==1.24.4", + "pandas==2.0.3", + "powerlaw==1.5", + "pyarrow==13.0.0", + "pyyaml==6.0.1", + "scikit-learn==1.3.2", + "scipy==1.10.1", + "seaborn==0.13.0", + "tables==3.8.0", + "tqdm==4.66.1", + "xgboost==2.0.0", +] +readme = "README.md" +license = { text = "MIT license" } +requires-python = ">=3.8" +classifiers = [ + "Programming Language :: Rust", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] + +[build-system] +requires = ["maturin>=1,<2"] +build-backend = "maturin" + +[tool.maturin] +features = ["pyo3/extension-module"] +python-source = "python" +module-name = "funmap._lib" + +[tool.rye] +managed = true +dev-dependencies = ["maturin>=1.7.4"] diff --git a/pyproject_maturin.toml b/pyproject_maturin.toml new file mode 100644 index 00000000..bb2585da --- /dev/null +++ b/pyproject_maturin.toml @@ -0,0 +1,16 @@ +[build-system] +requires = ["maturin>=1.7,<2.0"] +build-backend = "maturin" + +[project] +name = "funmap" +requires-python = ">=3.8" +classifiers = [ + "Programming Language :: Rust", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] +dynamic = ["version"] +[tool.maturin] +features = ["pyo3/extension-module"] +python-source = "funmap" diff --git a/funmap/__init__.py b/python/funmap/__init__.py similarity index 100% rename from funmap/__init__.py rename to python/funmap/__init__.py diff --git a/funmap/cli.py b/python/funmap/cli.py similarity index 99% rename from funmap/cli.py rename to python/funmap/cli.py index 3560eeb4..09640f4f 100644 --- a/funmap/cli.py +++ b/python/funmap/cli.py @@ -6,7 +6,7 @@ import click import numpy as np import pandas as pd - +from funmap import _lib as funmap_lib from funmap import __version__ from funmap.data_urls import misc_urls as urls from funmap.funmap import ( @@ -86,6 +86,11 @@ def qc(config_file, force_rerun): log.info("QC complete") +@cli.command() +def rust(): + print(f"sum: {funmap_lib.sum_as_string(5, 10)}") + + @cli.command(help="run funmap") @click.option( "--config-file", diff --git a/funmap/data_urls.py b/python/funmap/data_urls.py similarity index 100% rename from funmap/data_urls.py rename to python/funmap/data_urls.py diff --git a/funmap/funmap.py b/python/funmap/funmap.py similarity index 100% rename from funmap/funmap.py rename to python/funmap/funmap.py diff --git a/funmap/logger.py b/python/funmap/logger.py similarity index 100% rename from funmap/logger.py rename to python/funmap/logger.py diff --git a/funmap/plotting.py b/python/funmap/plotting.py similarity index 100% rename from funmap/plotting.py rename to python/funmap/plotting.py diff --git a/funmap/saving.py b/python/funmap/saving.py similarity index 100% rename from funmap/saving.py rename to python/funmap/saving.py diff --git a/funmap/utils.py b/python/funmap/utils.py similarity index 100% rename from funmap/utils.py rename to python/funmap/utils.py diff --git a/requirements-dev.lock b/requirements-dev.lock new file mode 100644 index 00000000..d3de5995 --- /dev/null +++ b/requirements-dev.lock @@ -0,0 +1,116 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: false +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +blosc2==2.0.0 + # via tables +click==8.1.7 + # via funmap +contourpy==1.3.0 + # via matplotlib +cycler==0.12.1 + # via matplotlib +cython==3.0.11 + # via tables +fonttools==4.54.1 + # via matplotlib +h5py==3.10.0 + # via funmap +imbalanced-learn==0.11.0 + # via funmap +joblib==1.3.2 + # via funmap + # via imbalanced-learn + # via scikit-learn +kiwisolver==1.4.7 + # via matplotlib +matplotlib==3.7.3 + # via funmap + # via matplotlib-venn + # via powerlaw + # via seaborn +matplotlib-venn==0.11.9 + # via funmap +maturin==1.7.4 +mpmath==1.3.0 + # via powerlaw +msgpack==1.1.0 + # via blosc2 +networkx==3.1 + # via funmap +numexpr==2.10.1 + # via tables +numpy==1.24.4 + # via contourpy + # via funmap + # via h5py + # via imbalanced-learn + # via matplotlib + # via matplotlib-venn + # via numexpr + # via pandas + # via powerlaw + # via pyarrow + # via scikit-learn + # via scipy + # via seaborn + # via tables + # via xgboost +packaging==24.1 + # via matplotlib + # via tables +pandas==2.0.3 + # via funmap + # via seaborn +pillow==10.4.0 + # via matplotlib +powerlaw==1.5 + # via funmap +py-cpuinfo==9.0.0 + # via tables +pyarrow==13.0.0 + # via funmap +pyparsing==3.1.4 + # via matplotlib +pypdf2==3.0.1 + # via funmap +python-dateutil==2.9.0.post0 + # via matplotlib + # via pandas +pytz==2024.2 + # via pandas +pyyaml==6.0.1 + # via funmap +scikit-learn==1.3.2 + # via funmap + # via imbalanced-learn +scipy==1.10.1 + # via funmap + # via imbalanced-learn + # via matplotlib-venn + # via powerlaw + # via scikit-learn + # via xgboost +seaborn==0.13.0 + # via funmap +six==1.16.0 + # via python-dateutil +tables==3.8.0 + # via funmap +threadpoolctl==3.5.0 + # via imbalanced-learn + # via scikit-learn +tqdm==4.66.1 + # via funmap +tzdata==2024.2 + # via pandas +xgboost==2.0.0 + # via funmap diff --git a/requirements.lock b/requirements.lock new file mode 100644 index 00000000..4ca03409 --- /dev/null +++ b/requirements.lock @@ -0,0 +1,115 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: false +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +blosc2==2.0.0 + # via tables +click==8.1.7 + # via funmap +contourpy==1.3.0 + # via matplotlib +cycler==0.12.1 + # via matplotlib +cython==3.0.11 + # via tables +fonttools==4.54.1 + # via matplotlib +h5py==3.10.0 + # via funmap +imbalanced-learn==0.11.0 + # via funmap +joblib==1.3.2 + # via funmap + # via imbalanced-learn + # via scikit-learn +kiwisolver==1.4.7 + # via matplotlib +matplotlib==3.7.3 + # via funmap + # via matplotlib-venn + # via powerlaw + # via seaborn +matplotlib-venn==0.11.9 + # via funmap +mpmath==1.3.0 + # via powerlaw +msgpack==1.1.0 + # via blosc2 +networkx==3.1 + # via funmap +numexpr==2.10.1 + # via tables +numpy==1.24.4 + # via contourpy + # via funmap + # via h5py + # via imbalanced-learn + # via matplotlib + # via matplotlib-venn + # via numexpr + # via pandas + # via powerlaw + # via pyarrow + # via scikit-learn + # via scipy + # via seaborn + # via tables + # via xgboost +packaging==24.1 + # via matplotlib + # via tables +pandas==2.0.3 + # via funmap + # via seaborn +pillow==10.4.0 + # via matplotlib +powerlaw==1.5 + # via funmap +py-cpuinfo==9.0.0 + # via tables +pyarrow==13.0.0 + # via funmap +pyparsing==3.1.4 + # via matplotlib +pypdf2==3.0.1 + # via funmap +python-dateutil==2.9.0.post0 + # via matplotlib + # via pandas +pytz==2024.2 + # via pandas +pyyaml==6.0.1 + # via funmap +scikit-learn==1.3.2 + # via funmap + # via imbalanced-learn +scipy==1.10.1 + # via funmap + # via imbalanced-learn + # via matplotlib-venn + # via powerlaw + # via scikit-learn + # via xgboost +seaborn==0.13.0 + # via funmap +six==1.16.0 + # via python-dateutil +tables==3.8.0 + # via funmap +threadpoolctl==3.5.0 + # via imbalanced-learn + # via scikit-learn +tqdm==4.66.1 + # via funmap +tzdata==2024.2 + # via pandas +xgboost==2.0.0 + # via funmap diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..38f97a17 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,14 @@ +use pyo3::prelude::*; + +/// Formats the sum of two numbers as string. +#[pyfunction] +fn sum_as_string(a: usize, b: usize) -> PyResult { + Ok((a + b).to_string()) +} + +/// A Python module implemented in Rust. +#[pymodule] +fn _lib(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; + Ok(()) +}