Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vpdq] Use scikit-build-core build backend for Python binding #1721

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions .github/workflows/vpdq-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,27 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install packaging dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r packaging-requirements.txt
python-version: "3.11"
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-dev pkg-config cmake ffmpeg libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libswresample-dev libavfilter-dev

- name: Install packaging dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r packaging-requirements.txt
python -m pip list

- name: Package
run: |
python -m build --sdist

- name: Ensure packaged build runs
run: |
python -m pip install dist/vpdq*.tar.gz
python -c "import vpdq"
python -m pip list
python -c "import vpdq; print(dir(vpdq))"

- name: Publish distribution to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ pdq/java/bazel-testlogs/
.vscode/
*.d.ts
.idea/
venv/
venv/
.venv/
210 changes: 205 additions & 5 deletions vpdq/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# vpdq
output-hashes/*
python/vpdq.cpp

# Misc
*.o
*.a
*.dSYM
Expand All @@ -8,12 +13,207 @@
*.swp
*.swo

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
cpp/libraries-dirs.txt
cpp/test
cpp/build
output-hashes/*
python/vpdq.cpp
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

# CMake
CMakeLists.txt.user
Expand Down
45 changes: 45 additions & 0 deletions vpdq/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# CMake to build the Python binding for vpdq. This is built with the Python
# scikit-build-core build backend. This compiles vpdq and compiles the Cython
# and then links vpdq to the compiled Cython.

cmake_minimum_required(VERSION 3.15...3.30)
project(${SKBUILD_PROJECT_NAME} LANGUAGES CXX)

set(CMAKE_CXX_STANDARD
14
CACHE STRING "C++ version selection")
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Compile pdq and vpdq to produce their library files.
add_subdirectory(cpp)

# Build the Cython bindings. Create the cpp file from the Cython pyx file,
# compile it, and link it to vpdq.

find_package(
Python
COMPONENTS Interpreter Development.Module
REQUIRED)

add_custom_command(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/python/vpdq.cpp
COMMENT
"Making ${CMAKE_CURRENT_BINARY_DIR}/python/vpdq.cpp from ${CMAKE_CURRENT_SOURCE_DIR}/python/vpdq.pyx"
COMMAND
Python::Interpreter -m cython "${CMAKE_CURRENT_SOURCE_DIR}/python/vpdq.pyx"
--output-file "${CMAKE_CURRENT_SOURCE_DIR}/python/vpdq.cpp"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/python/vpdq.pyx
VERBATIM)

python_add_library(vpdq MODULE ${CMAKE_CURRENT_SOURCE_DIR}/python/vpdq.cpp
WITH_SOABI)

# Link pdq and vpdq to the vpdq Cython library
target_link_libraries(vpdq PUBLIC pdqlib)
target_link_libraries(vpdq PUBLIC vpdqlib)

# Note: The install directory determines the module directory. For example, if
# it's changed to 'foo', then in python you would have to do 'from foo import
# vpdq' to use the module. Leaving it at '.' allows for just 'import vpdq'.
install(TARGETS vpdq DESTINATION .)
10 changes: 4 additions & 6 deletions vpdq/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,15 @@ Install dependencies:
python -m pip install -r packaging-requirements.txt
```

Build package:
Build source distribution package:
```sh
python -m build --sdist
```

Build wheel:
```sh
python -m build --wheel
```
The package should now be in `dist/`.

The package/wheel should now be in `dist/`.
> **Note:** Wheels are not currently distributed. But, in the future building wheels with manylinux and packaging the dynamically
> linked libav* libraries may be useful to end users to skip the build and dependency process.

### Publishing

Expand Down
1 change: 0 additions & 1 deletion vpdq/MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ include README.md

graft cpp
prune cpp/build
exclude cpp/libraries-dirs.txt

graft python
6 changes: 0 additions & 6 deletions vpdq/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,3 @@ add_subdirectory(vpdq)
# CLI programs
# TODO: Make this a custom command/option. This isn't necessary to just build the library.
add_subdirectory(apps)

# Write the libav* library dirs to a new-line delimited file for Cython to be able to locate LIBAV files
# TODO: Make this a custom command or something. This isn't necessary on every run.
string(REPLACE ";" "\n" LIBRARY_DIRS "${LIBAV_STATIC_LIBRARY_DIRS}")
set(LIBRARY_DIRS_FILE "libraries-dirs.txt")
file(WRITE ${LIBRARY_DIRS_FILE} "${LIBRARY_DIRS}")
37 changes: 22 additions & 15 deletions vpdq/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
[build-system]
requires = [
"setuptools >= 61.0",
"wheel",
"cython",
"cmake",
]
build-backend = "setuptools.build_meta"
requires = ["scikit-build-core", "cython"]
build-backend = "scikit_build_core.build"

[project]
name = "vpdq"
Expand All @@ -14,13 +9,25 @@ description = "Python bindings for Facebook VPDQ hash"
requires-python = ">= 3.8"
readme = {file = "python/README.md", content-type = "text/markdown"}
license = {file = "LICENSE.txt"}
dynamic = ["version", "scripts", "entry-points"]
dynamic = ["version"]

[tool.scikit-build.metadata.version]
provider = "scikit_build_core.metadata.regex"
input = "version.txt"

[tool.setuptools]
include-package-data = true
# Regex explanation:
# ^ matches the start of the line.
# ?P<value> is the named capture group with the name value. scikit is expecting this.
# \S+ matches any non-whitespace characters, assuming the version is a single token.
# $ ensures the match ends at the end of the line.
regex = "^(?P<value>\\S+)$"

[tool.setuptools.packages.find]
where = ["python"] # list of folders that contain the packages (["."] by default)
include = ["vpdq.pyx"] # package names should match these glob patterns (["*"] by default)
exclude = [] # exclude packages matching these glob patterns (empty by default)
namespaces = false # to disable scanning PEP 420 namespaces (true by default)
[tool.scikit-build]
minimum-version = "0.10"
cmake.build-type = "RelWithDebInfo"

[project.optional-dependencies]
dev = [
"pytest",
"clang-format",
]
Loading
Loading