Skip to content
Merged
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
167 changes: 162 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version: 2.1
orbs:
slack: circleci/slack@4.4.2
python: circleci/python@2.1.0
win: circleci/windows@5.0

jobs:
build_test:
Expand Down Expand Up @@ -75,11 +76,16 @@ jobs:
event: fail
template: basic_fail_1

pypi_publish:
build_sdist:
docker:
- image: cimg/python:3.10

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should this be the same as line 14? - image: python:3.10-bullseye

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah it doesn't matter, the previous tests used the debian bullseye image so I just stuck to that convention

steps:
- checkout # checkout source code to working directory
- run:
name: Install Build Tools
command: |
pip install --upgrade pip
pip install poetry
- run:
name: Validate Tag Version # Check if the tag name matches the package version
command: |
Expand All @@ -99,9 +105,121 @@ jobs:
exit 1;
fi
- run:
name: Build
name: Build sdist
command: | # install env dependencies
poetry build
rm -rf dist
poetry build --format sdist
- persist_to_workspace:
root: .
paths:
- dist

build_linux_wheels:
docker:
- image: cimg/python:3.10
steps:
- checkout # checkout source code to working directory
- setup_remote_docker
- run:
name: Build Linux wheels
command: |
pip install --upgrade pip
pip install cibuildwheel

export CIBW_ARCHS_LINUX="x86_64"
export CIBW_BUILD="cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp312-manylinux_x86_64 cp313-manylinux_x86_64 cp314-manylinux_x86_64"
export CIBW_SKIP="pp* *-musllinux_*"
export CIBW_TEST_COMMAND='python -c "import nucleus._native_dedup as native; assert native.deduplicate_phashes([0, 1023, 2047], 10) == [0, 2]"'
python -m cibuildwheel --platform linux --output-dir dist

ls -lh dist
- persist_to_workspace:
root: .
paths:
- dist

build_macos_wheels:
macos:
xcode: 16.4.0
resource_class: m4pro.medium
steps:
- checkout # checkout source code to working directory
- run:
name: Build macOS wheels
command: |
python3 -m pip install --upgrade pip
python3 -m pip install cibuildwheel
softwareupdate --install-rosetta --agree-to-license || true

export CIBW_ARCHS_MACOS="universal2"
export CIBW_BUILD="cp310-macosx_* cp311-macosx_* cp312-macosx_* cp313-macosx_* cp314-macosx_*"
export CIBW_SKIP="pp*"
export CIBW_TEST_COMMAND='python -c "import nucleus._native_dedup as native; assert native.deduplicate_phashes([0, 1023, 2047], 10) == [0, 2]"'
python3 -m cibuildwheel --platform macos --output-dir dist

ls -lh dist
- persist_to_workspace:
root: .
paths:
- dist

build_windows_wheels:
executor:
name: win/default
size: medium
steps:
- checkout # checkout source code to working directory
- run:
name: Build Windows wheels
command: |
python -m pip install --upgrade pip
python -m pip install cibuildwheel

$env:CIBW_BUILD = "cp310-win_amd64 cp311-win_amd64 cp312-win_amd64 cp313-win_amd64 cp314-win_amd64"
$env:CIBW_SKIP = "pp*"
$env:CIBW_TEST_COMMAND = 'python -c "import nucleus._native_dedup as native; assert native.deduplicate_phashes([0, 1023, 2047], 10) == [0, 2]"'
python -m cibuildwheel --platform windows --output-dir dist

Get-ChildItem dist
- persist_to_workspace:
root: .
paths:
- dist

pypi_publish:
docker:
- image: cimg/python:3.10
steps:
- checkout # checkout source code to working directory
- attach_workspace:
at: .
- run:
name: Install Publish Tools
command: |
pip install --upgrade pip
pip install poetry
- run:
name: Validate Tag Version # Check if the tag name matches the package version
command: |
PKG_VERSION=$(sed -n 's/^version = //p' pyproject.toml | sed -e 's/^"//' -e 's/"$//')
if [[ "$CIRCLE_TAG" != "v${PKG_VERSION}" ]]; then
echo "ERROR: Tag name ($CIRCLE_TAG) must match package version (v${PKG_VERSION})."
exit 1;
fi
- run:
name: Validate SDK Version Increment # Check if the version is already on PyPI
command: |
PKG_VERSION=$(sed -n 's/^version = //p' pyproject.toml | sed -e 's/^"//' -e 's/"$//')
if pip install "scale-nucleus>=${PKG_VERSION}" > /dev/null 2>&1;
then
echo "ERROR: You need to increment to a new version before publishing!"
echo "Version (${PKG_VERSION}) already exists on PyPI."
exit 1;
fi
- run:
name: List artifacts to publish
command: |
ls -lh dist
- run:
name: Publish to PyPI
command: |
Expand Down Expand Up @@ -165,12 +283,51 @@ workflows:
filters:
tags:
only: /^v\d+\.\d+\.\d+$/ # Runs only for tags with the format [v1.2.3]
- pypi_publish:
- build_sdist:
context: Nucleus
requires:
- build_test
filters:
branches:
ignore: /.*/ # Runs for none of the branches
tags:
only: /^v\d+\.\d+\.\d+$/ # Runs only for tags with the format [v1.2.3]

- build_linux_wheels:
context: Nucleus
requires:
- build_test
filters:
branches:
ignore: /.*/ # Runs for none of the branches
tags:
only: /^v\d+\.\d+\.\d+$/ # Runs only for tags with the format [v1.2.3]
- build_macos_wheels:
context: Nucleus
requires:
- build_test
filters:
branches:
ignore: /.*/ # Runs for none of the branches
tags:
only: /^v\d+\.\d+\.\d+$/ # Runs only for tags with the format [v1.2.3]
- build_windows_wheels:
context: Nucleus
requires:
- build_test
filters:
branches:
ignore: /.*/ # Runs for none of the branches
tags:
only: /^v\d+\.\d+\.\d+$/ # Runs only for tags with the format [v1.2.3]
- pypi_publish:
context: Nucleus
requires:
- build_sdist
- build_linux_wheels
- build_macos_wheels
- build_windows_wheels
filters:
branches:
ignore: /.*/ # Runs for none of the branches
tags:
only: /^v\d+\.\d+\.\d+$/ # Runs only for tags with the format [v1.2.3]
11 changes: 9 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ All notable changes to the [Nucleus Python Client](https://github.com/scaleapi/n
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.18.5](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.18.4) - 2026-05-28
## [0.18.6](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.18.6) - 2026-06-15

### Added
- Native C acceleration for `deduplicate_by_phash`. When the compiled extension is available, all threshold values are handled in native code: thresholds `0` through `11` use the chunked Hamming index, thresholds `12` through `63` use a native linear scan, and threshold `64` uses the keep-first fast path. The public Python API is unchanged and falls back to the pure-Python implementation when the native extension is unavailable.

- **Evaluations V2** client support for COCO-style metrics on model runs via stored `evaluation_match_v2` rows. `NucleusClient` exposes `create_evaluation_v2()`, `get_evaluation_v2()`, and `list_evaluations_v2()`. The `EvaluationV2` resource supports `wait_for_completion()`, `charts()` (mAP, confusion matrix, PR curve, TIDE, and related aggregates), `examples()` (paginated TP/FP/FN rows), `delete()`, and `refresh()`. `AllowedLabelMatch` configures allowed ground-truth / prediction label pairs; filter and response types include `EvaluationV2FilterArgs`, `EvaluationV2Charts`, `EvaluationV2ExamplesPage`, and `EvaluationV2MatchExample`. Sphinx docs cover the workflow under Evaluations V2.
### Tooling / CI
- Publish Linux `x86_64`, macOS `universal2`, and Windows `amd64` wheels for Python 3.10 through 3.14 using `cibuildwheel`, alongside the source distribution.

## [0.18.5](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.18.5) - 2026-05-28

### Added

- **Evaluations V2** client support for COCO-style metrics on model runs via stored `evaluation_match_v2` rows. `NucleusClient` exposes `create_evaluation_v2()`, `get_evaluation_v2()`, and `list_evaluations_v2()`. The `EvaluationV2` resource supports `wait_for_completion()`, `charts()` (mAP, confusion matrix, PR curve, TIDE, and related aggregates), `examples()` (paginated TP/FP/FN rows), `delete()`, and `refresh()`. `AllowedLabelMatch` configures allowed ground-truth / prediction label pairs; filter and response types include `EvaluationV2FilterArgs`, `EvaluationV2Charts`, `EvaluationV2ExamplesPage`, and `EvaluationV2MatchExample`. Sphinx docs cover the workflow under Evaluations V2.

## [0.18.4](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.18.4) - 2026-06-08

Expand Down
24 changes: 24 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from __future__ import annotations

import sys

from setuptools import Extension


def build(setup_kwargs):
extra_compile_args = []
if sys.platform != "win32":
extra_compile_args.extend(["-std=c11", "-O3"])

setup_kwargs.update(
{
"ext_modules": [
Extension(
"nucleus._native_dedup",
["nucleus/_native_dedup.c"],
extra_compile_args=extra_compile_args,
optional=True,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense that this is optional and this probably won't happen, but curious once this is deployed, is it possible for you/the user who runs this dedup function to see if the C code is actually running or if its falling back to the python-based version. ie. could we detect if some weird/strange error occurred that causes the C code to never/barely run on user's who should be able to support C-mode?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting, I don't know I'll look into it. I guess the in general clients don't have visibility into SDKs although nucleus-python-client is open source.

)
],
}
)
Loading