python-perspective

maintainer thrasibule · 0 votes · scanned 2026-08-03 00:08:14.047287
LOW
View on AUR ↗
Why flagged The package builds from source and only vendors prebuilt JupyterLab extension assets from PyPI, which are non-executable data; the core binary is compiled locally, and the source is from a trusted upstream repository.

Triggered rules

LOW Few votes, recently uploaded zero_votes_recent

Uploaded within the last 14 days with 2 or fewer community votes — little peer review so far.

LOW AI review llm_review

An AI model (qwen/qwen3-235b-a22b-2507) reviewed this and agrees it is LOW (confidence 95%): The package builds from source and only vendors prebuilt JupyterLab extension assets from PyPI, which are non-executable data; the core binary is compiled locally, and the source is from a trusted upstream repository.

PKGBUILD

1# Maintainer: Guillaume Horel <guillaume.horel@gmail.com>
2
3pkgname=python-perspective
4_pkgname=perspective
5pkgver=4.5.2
6pkgrel=1
7pkgdesc="Python bindings for Perspective, a high performance data-visualization and analytics component"
8url="https://github.com/perspective-dev/perspective"
9license=('Apache-2.0')
10arch=('x86_64')
11depends=('python' 'gcc-libs' 'glibc' 'abseil-cpp' 'protobuf')
12makedepends=('cargo' 'cmake' 'maturin' 'python-build' 'python-installer' 'git' 'protobuf')
13# The jupyterlab labextension's JS bundle requires nightly Rust to compile
14# `perspective-viewer` to wasm (it uses iter_intersperse / try_blocks /
15# more_qualified_paths). Rather than build a nightly toolchain, vendor the
16# prebuilt labextension bytes from the official PyPI wheel (same upstream
17# version we build the rest from) and graft them onto our wheel via maturin's
18# `data = ...` directive. Our .so is still built from source.
19_upstream_whl=perspective_python-${pkgver}-cp311-abi3-manylinux_2_28_x86_64.whl
20source=("https://github.com/perspective-dev/perspective/archive/refs/tags/v$pkgver.tar.gz"
21 "https://files.pythonhosted.org/packages/89/94/94c06faff7430c8b5c48bed41da759e1e4894528b2e2373617adf9d5f1e4/${_upstream_whl}")
22sha512sums=('46fc86ac07a4457f79e0a571d939540678d8bfce8bdce19bbcaceb5d7861c15aa153f71774211d426e2ad5748b7d55482aa9e91500e5cf0daa32ace51f43251e'
23 '36500ccf7eadb33098ccda45205b829dbadc8352266eb5a44c4ac5c60bd50dfedebfe810f46be59da18a2374c59c1fa7924435700c75531b706e4f61bf51faa1')
24
25prepare() {
26 cd "$_pkgname-$pkgver"
27 # Drop workspace members that require nightly Cargo (`-Z bindeps`)
28 sed -i '/"rust\/lint",/d;/"rust\/metadata",/d;/"rust\/bundle",/d;/"examples\/rust-axum",/d' Cargo.toml
29
30 # Expose perspective-client's `omit_metadata` feature through perspective-python
31 # so we can skip pulling in `docs/expression_gen.md` (generated by the metadata
32 # crate, which we just removed from the workspace).
33 sed -i '/^default = \[\]$/a omit_metadata = ["perspective-client/omit_metadata"]' \
34 rust/perspective-python/Cargo.toml
35
36 # Force the C++ archive containing the psp_* FFI exports to be whole-archive
37 # linked. Without this the rust linker leaves binding_api.cpp.o out and the
38 # cdylib comes out missing every psp_* symbol at import time. Only apply the
39 # modifier to libpsp; the recursive walk emits some library names twice
40 # (e.g. lz4) and rustc rejects duplicates that disagree on modifiers. Also
41 # teach the walk to skip libpsp so its modifier-less re-emission doesn't
42 # collide with the explicit `+whole-archive=psp` declaration.
43 sed -i 's|cargo:rustc-link-lib=static=psp|cargo:rustc-link-lib=static:+whole-archive,-bundle=psp|' \
44 rust/perspective-server/build.rs
45 sed -i 's|println!("cargo:rustc-link-lib=static={a}");|if a != "psp" { println!("cargo:rustc-link-lib=static={a}"); }|' \
46 rust/perspective-server/build.rs
47
48 # Use the system protobuf (Arch's /usr/bin/protoc + /usr/lib/libprotobuf.so)
49 # rather than have perspective's cmake fetch and build a vendored copy.
50 # Swap psp_build_dep("protobuf", ...) for find_package(Protobuf REQUIRED)
51 # in the protos sub-build, and drop the obsolete include-dir line that
52 # pointed into the vendored protobuf source tree.
53 sed -i 's|psp_build_dep("protobuf".*|find_package(Protobuf REQUIRED)|' \
54 rust/perspective-server/cpp/protos/CMakeLists.txt
55 sed -i '/target_include_directories(protos PRIVATE \${CMAKE_CURRENT_BINARY_DIR}\/protobuf-src\/src)/d' \
56 rust/perspective-server/cpp/protos/CMakeLists.txt
57
58 # Point perspective-server's cmake at system protoc instead of the vendored
59 # one from the protobuf-src crate (v27.1), so the generated .pb.cc matches
60 # the system libprotobuf headers/ABI.
61 perl -i -0pe 's|protoc\(\)\s*\.parent\(\)\s*\.expect\("protoc\(\) returned root path or empty string"\),|std::path::PathBuf::from("/usr/bin"),|' \
62 rust/perspective-server/build.rs
63
64 # The cmake walk in build.rs would normally link the vendored libprotobuf.a
65 # the bundled build produces. With find_package we link the system .so
66 # instead — emitted alongside the system absl dylibs below.
67 sed -i 's|cmake_link_deps(\&artifact_dir)?;|cmake_link_deps(\&artifact_dir)?;\n link_system_protobuf_absl()?;|' \
68 rust/perspective-server/build.rs
69 cat >> rust/perspective-server/build.rs <<'RUSTEOF'
70
71fn link_system_protobuf_absl() -> Result<(), std::io::Error> {
72 // perspective's bundled protobuf picks up the *system* abseil-cpp via
73 // find_package() during its cmake build, so libprotobuf.so carries
74 // references to abseil's versioned (`lts_…`) mangled names. Link the
75 // system protobuf and every system libabsl_*.so dynamically so those
76 // references resolve at module-load time. Arch ships these as shared
77 // libs under /usr/lib/libabsl_*.so (each a symlink onto a versioned
78 // .so.N.M.P).
79 println!("cargo:rustc-link-lib=dylib=protobuf");
80 let lib_dir = std::path::Path::new("/usr/lib");
81 for entry in fs::read_dir(lib_dir)? {
82 let path = entry?.path();
83 let name = match path.file_name().and_then(|n| n.to_str()) {
84 Some(s) => s.to_string(),
85 None => continue,
86 };
87 if let Some(stem) = name.strip_prefix("lib").and_then(|s| s.strip_suffix(".so"))
88 && stem.starts_with("absl_")
89 {
90 println!("cargo:rustc-link-lib=dylib={stem}");
91 }
92 }
93 Ok(())
94}
95RUSTEOF
96
97 cd rust/perspective-python
98 cp ../../LICENSE.md .
99
100 # Graft the prebuilt jupyterlab labextension (JS + perspective-viewer wasm)
101 # from the upstream PyPI wheel into our `data` directory so maturin packages
102 # it into our wheel under `usr/share/jupyter/labextensions/`. We only take
103 # the .data tree from the upstream wheel; everything else (the .so, the
104 # python sources, the dist-info) comes from our local build.
105 rm -rf "perspective_python-$pkgver.data"
106 bsdtar -xf "$srcdir/$_upstream_whl" "perspective_python-$pkgver.data/data/share/jupyter/*"
107}
108
109build() {
110 cd "$_pkgname-$pkgver/rust/perspective-python"
111 export PSP_ROOT_DIR=../..
112 # makepkg adds `-flto=auto` to CXX/CFLAGS by default. With only LTO bitcode
113 # in the .o files, the rust linker can't see the C++ symbols in libpsp.a et
114 # al. and the cdylib comes out without any psp_*/arrow/protobuf symbols.
115 # Force fat-LTO objects so each .o carries both the bitcode and normal ELF
116 # code; the linker then has something to pull in from the static archives.
117 export CFLAGS+=" -ffat-lto-objects"
118 export CXXFLAGS+=" -ffat-lto-objects"
119 maturin build --release --features=generate-proto,protobuf-src,omit_metadata --interpreter python
120}
121
122package() {
123 cd "$_pkgname-$pkgver"
124 python -m installer --destdir="$pkgdir" rust/target/wheels/*.whl
125 install -Dm644 LICENSE.md -t "$pkgdir/usr/share/licenses/$pkgname/"
126}
127

Changes since previous scan

--- PKGBUILD @ 2026-07-24 00:02
+++ PKGBUILD @ 2026-08-03 00:08
@@ -1,4 +1,4 @@
-# Maintainer: Guillaume Horel <ghorel@lmcg.com>
+# Maintainer: Guillaume Horel <guillaume.horel@gmail.com>
pkgname=python-perspective
_pkgname=perspective

Scan history

Scanned at (UTC)SeverityRules
2026-08-03 00:08:14 LOW 2
2026-08-02 00:16:08 LOW 2
2026-08-01 00:11:18 LOW 2
2026-07-31 00:14:10 LOW 2
2026-07-30 00:17:23 LOW 2
2026-07-29 00:25:53 LOW 2
2026-07-28 00:07:28 LOW 2
2026-07-27 00:24:32 LOW 2
2026-07-26 00:07:32 LOW 2
2026-07-25 00:13:44 LOW 2
2026-07-24 13:27:52 LOW 2
2026-07-24 00:02:28 LOW 2
2026-07-23 00:14:47 LOW 2
2026-07-22 23:22:13 LOW 2

Report a package

Reports go to the AURWatch maintainer (one person) and are read by hand. No login required.

0 / 4000
Your suggestion