From 1f45cb4cb075a33e1139a74b022e6e9260879e01 Mon Sep 17 00:00:00 2001 From: Leo Razoumov Date: Sun, 6 Nov 2022 03:36:39 -0500 Subject: [PATCH] feat(python,rust): build_info() provides detailed information how polars was built (#5423) --- py-polars/Cargo.lock | 164 ++++++++++++++++++++++++ py-polars/Cargo.toml | 6 + py-polars/build.rs | 19 +++ py-polars/polars/__init__.py | 5 +- py-polars/polars/build_info.py | 29 +++++ py-polars/src/lib.rs | 17 +++ py-polars/tests/unit/test_build_info.py | 9 ++ 7 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 py-polars/build.rs create mode 100644 py-polars/polars/build_info.py create mode 100644 py-polars/tests/unit/test_build_info.py diff --git a/py-polars/Cargo.lock b/py-polars/Cargo.lock index f53c2a9886cb..80cdb89d9c69 100644 --- a/py-polars/Cargo.lock +++ b/py-polars/Cargo.lock @@ -221,6 +221,17 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "built" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f346b6890a0dfa7266974910e7df2d5088120dd54721b9b0e5aae1ae5e05715" +dependencies = [ + "cargo-lock", + "chrono", + "git2", +] + [[package]] name = "bumpalo" version = "3.11.1" @@ -253,6 +264,18 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cargo-lock" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c408da54db4c50d4693f7e649c299bc9de9c23ead86249e5368830bb32a734b" +dependencies = [ + "semver", + "serde", + "toml", + "url", +] + [[package]] name = "cc" version = "1.0.74" @@ -569,6 +592,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee1b05cbd864bcaecbd3455d6d967862d446e4ebfc3c2e5e5b9841e53cba6673" +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fs_extra" version = "1.2.0" @@ -697,6 +729,19 @@ dependencies = [ "syn", ] +[[package]] +name = "git2" +version = "0.13.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "glob" version = "0.3.0" @@ -775,6 +820,16 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "1.9.1" @@ -965,6 +1020,18 @@ dependencies = [ "rle-decode-fast", ] +[[package]] +name = "libgit2-sys" +version = "0.12.26+1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libm" version = "0.2.5" @@ -980,6 +1047,18 @@ dependencies = [ "cc", ] +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "link-cplusplus" version = "1.0.7" @@ -1290,6 +1369,12 @@ dependencies = [ "regex", ] +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + [[package]] name = "phf" version = "0.11.1" @@ -1341,6 +1426,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + [[package]] name = "planus" version = "0.3.1" @@ -1556,6 +1647,7 @@ version = "0.14.25" dependencies = [ "ahash 0.8.1", "bincode", + "built", "jemallocator", "libc", "mimalloc", @@ -1566,6 +1658,7 @@ dependencies = [ "polars-core", "polars-lazy", "pyo3", + "pyo3-built", "serde_json", "thiserror", ] @@ -1597,6 +1690,12 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "pyo3-built" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be6d574e0f8cab2cdd1eeeb640cbf845c974519fa9e9b62fa9c08ecece0ca5de" + [[package]] name = "pyo3-ffi" version = "0.16.6" @@ -1776,6 +1875,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +[[package]] +name = "semver" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +dependencies = [ + "serde", +] + [[package]] name = "seq-macro" version = "0.3.1" @@ -2014,6 +2122,30 @@ dependencies = [ "winapi", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + [[package]] name = "uncased" version = "0.9.7" @@ -2023,12 +2155,27 @@ dependencies = [ "version_check", ] +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + [[package]] name = "unicode-ident" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-width" version = "0.1.10" @@ -2041,6 +2188,17 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58ee9362deb4a96cef4d437d1ad49cffc9b9e92d202b6995674e928ce684f112" +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "value-trait" version = "0.5.0" @@ -2053,6 +2211,12 @@ dependencies = [ "ryu", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" diff --git a/py-polars/Cargo.toml b/py-polars/Cargo.toml index 7bb836f33aa6..2617535ce2b7 100644 --- a/py-polars/Cargo.toml +++ b/py-polars/Cargo.toml @@ -31,6 +31,7 @@ once_cell = "1" polars-core = { path = "../polars/polars-core", default-features = false } polars-lazy = { path = "../polars/polars-lazy", features = ["python"], default-features = false } pyo3 = { version = "0.16", features = ["abi3-py37", "extension-module", "multiple-pymethods"] } +pyo3-built = { version = "0.4", optional = true } serde_json = { version = "1", optional = true } thiserror = "^1.0" @@ -60,6 +61,7 @@ pivot = ["polars/pivot"] top_k = ["polars/top_k"] propagate_nans = ["polars/propagate_nans"] sql = ["polars/sql"] +build_info = ["dep:pyo3-built", "dep:built"] all = [ "json", @@ -83,6 +85,7 @@ all = [ "object", "pivot", "top_k", + "build_info", # we need to add this, as maturin fails if we don't # remove this once polars-algo is released "polars/algo", @@ -170,3 +173,6 @@ lto = "fat" # This is ignored here; would be set in .cargo/config.toml. # Should not be used when packaging # target-cpu = "native" + +[build-dependencies] +built = { version = "0.5", features = ["chrono", "git2"], optional = true } diff --git a/py-polars/build.rs b/py-polars/build.rs new file mode 100644 index 000000000000..5b52c8858f4d --- /dev/null +++ b/py-polars/build.rs @@ -0,0 +1,19 @@ +/// Build script using 'built' crate to generate build info. + +fn main() { + #[cfg(feature = "build_info")] + { + extern crate built; + use std::env; + use std::path::Path; + + let src = env::var("CARGO_MANIFEST_DIR").unwrap(); + let dst = Path::new(&env::var("OUT_DIR").unwrap()).join("built.rs"); + let mut opts = built::Options::default(); + + opts.set_dependencies(true).set_compiler(true).set_env(true); + + built::write_built_file_with_opts(&opts, Path::new(&src), &dst) + .expect("Failed to acquire build-time information"); + } +} diff --git a/py-polars/polars/__init__.py b/py-polars/polars/__init__.py index e836438d7e8e..23d7f576272e 100644 --- a/py-polars/polars/__init__.py +++ b/py-polars/polars/__init__.py @@ -1,3 +1,4 @@ +import os import warnings try: @@ -10,6 +11,7 @@ def version() -> str: # this is only useful for documentation warnings.warn("polars binary missing!") +from polars.build_info import build_info from polars.cfg import Config from polars.convert import ( from_arrow, @@ -291,11 +293,10 @@ def version() -> str: "threadpool_size", # version "show_versions", + "build_info", "SQLContext", ] __version__ = version() -import os - os.environ["POLARS_ALLOW_EXTENSION"] = "true" diff --git a/py-polars/polars/build_info.py b/py-polars/polars/build_info.py new file mode 100644 index 000000000000..dad32d254551 --- /dev/null +++ b/py-polars/polars/build_info.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from typing import Any + +try: + from polars.polars import version + + _version_ = version() +except ImportError: + _version_ = "" + +try: + from polars.polars import _build_info_ +except ImportError: + _build_info_ = {} + +_build_info_["version"] = _version_ + + +def build_info() -> dict[str, Any]: + """ + Return a dict with polars build information. + + If polars was compiled with "build_info" feature gate return the full build info, + otherwise only version is included. The full build information dict contains + the following keys ['build', 'info-time', 'dependencies', 'features', 'host', + 'target', 'git', 'version']. + """ + return _build_info_ diff --git a/py-polars/src/lib.rs b/py-polars/src/lib.rs index 687544a89041..3d243e67e690 100644 --- a/py-polars/src/lib.rs +++ b/py-polars/src/lib.rs @@ -4,6 +4,16 @@ extern crate core; extern crate polars; +#[cfg(feature = "build_info")] +#[macro_use] +extern crate pyo3_built; + +#[cfg(feature = "build_info")] +#[allow(dead_code)] +mod build { + include!(concat!(env!("OUT_DIR"), "/built.rs")); +} + pub mod apply; pub mod arrow_interop; #[cfg(feature = "csv-file")] @@ -568,6 +578,13 @@ fn polars(py: Python, m: &PyModule) -> PyResult<()> { py.get_type::(), ) .unwrap(); + + #[cfg(feature = "build_info")] + m.add( + "_build_info_", + pyo3_built!(py, build, "build", "time", "deps", "features", "host", "target", "git"), + )?; + m.add_class::().unwrap(); m.add_class::().unwrap(); m.add_class::().unwrap(); diff --git a/py-polars/tests/unit/test_build_info.py b/py-polars/tests/unit/test_build_info.py new file mode 100644 index 000000000000..cd9f73a40a66 --- /dev/null +++ b/py-polars/tests/unit/test_build_info.py @@ -0,0 +1,9 @@ +import polars as pl + + +def test_build_info() -> None: + build_info = pl.build_info() + assert "version" in build_info # version is always present + features = build_info.get("features", {}) + if features: # only when compiled with `build_info` feature gate + assert "BUILD_INFO" in features