Skip to content

refactor: migrate to uv#230

Draft
aditya-neuraco wants to merge 1 commit intodevelopfrom
refactor/migrate-everything-to-uv
Draft

refactor: migrate to uv#230
aditya-neuraco wants to merge 1 commit intodevelopfrom
refactor/migrate-everything-to-uv

Conversation

@aditya-neuraco
Copy link
Contributor

@aditya-neuraco aditya-neuraco commented Jan 8, 2026

Features

  • Migrate our software development lifecycle to uv where-ever possible.

Test Script

#!/usr/bin/env bash
set -euo pipefail

# Test script for UV migration workflows.
# Safe by default: runs local checks only unless optional flags are provided.

REPO_DEFAULT="/home/aditya/work/uv-migration"
REPO="${REPO_DEFAULT}"
RUN_PLATFORM_STAGING=false
RUN_PLATFORM_PRODUCTION=false
RUN_ML_STAGING=false
RUN_ML_PRODUCTION=false
RUN_RELEASE_CHECKS=false
INSTALL_ML_SYSTEM_DEPS=false
USE_CLEAN_HEAD=false
WORKTREE_DIR=""

log() {
  printf "\n[%s] %s\n" "$(date +"%H:%M:%S")" "$*"
}

warn() {
  printf "\n[WARN] %s\n" "$*"
}

die() {
  printf "\n[ERROR] %s\n" "$*" >&2
  exit 1
}

usage() {
  cat << USAGE
Usage: $(basename "$0") [options]

Options:
  --repo PATH                    Repo path (default: ${REPO_DEFAULT})
  --platform-staging             Run integration-platform staging test
  --platform-production          Run integration-platform production test
  --ml-staging                   Run integration-ml staging test
  --ml-production                Run integration-ml production test
  --release-checks               Run release workflow parity checks (dry-run only)
  --install-ml-system-deps       Install apt deps used by integration-ml (requires sudo)
  --clean-head                   Run checks from a temporary git worktree at HEAD
  --all                          Enable all optional checks above
  -h, --help                     Show this help

Credentials/env needed for optional integration checks:

  Platform staging:
    STAGING_NEURACORE_API_KEY
    STAGING_NEURACORE_ORG_ID

  Platform production:
    PROD_NEURACORE_API_KEY
    PROD_NEURACORE_ORG_ID

  ML staging:
    STAGING_NEURACORE_API_KEY
    STAGING_NEURACORE_ORG_ID

  ML production:
    PROD_NEURACORE_API_KEY
    PROD_NEURACORE_ORG_ID

Optional release dry-run publish auth (usually not required):
  PYPI_USERNAME
  PYPI_PASSWORD
USAGE
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --repo)
      [[ $# -ge 2 ]] || die "--repo requires a path"
      REPO="$2"
      shift 2
      ;;
    --platform-staging)
      RUN_PLATFORM_STAGING=true
      shift
      ;;
    --platform-production)
      RUN_PLATFORM_PRODUCTION=true
      shift
      ;;
    --ml-staging)
      RUN_ML_STAGING=true
      shift
      ;;
    --ml-production)
      RUN_ML_PRODUCTION=true
      shift
      ;;
    --release-checks)
      RUN_RELEASE_CHECKS=true
      shift
      ;;
    --install-ml-system-deps)
      INSTALL_ML_SYSTEM_DEPS=true
      shift
      ;;
    --clean-head)
      USE_CLEAN_HEAD=true
      shift
      ;;
    --all)
      RUN_PLATFORM_STAGING=true
      RUN_PLATFORM_PRODUCTION=true
      RUN_ML_STAGING=true
      RUN_ML_PRODUCTION=true
      RUN_RELEASE_CHECKS=true
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      die "Unknown option: $1"
      ;;
  esac
done

[[ -d "$REPO" ]] || die "Repo not found: $REPO"
cd "$REPO"

command -v uv >/dev/null 2>&1 || die "uv not found in PATH"
command -v git >/dev/null 2>&1 || die "git not found in PATH"

if [[ "$USE_CLEAN_HEAD" == "true" ]]; then
  log "Using clean git HEAD worktree (ignoring local uncommitted changes)"
  SOURCE_REPO="$REPO"
  git -C "$SOURCE_REPO" rev-parse --git-dir >/dev/null 2>&1 || die "Not a git repo: $SOURCE_REPO"
  WORKTREE_DIR="$(mktemp -d)"
  git -C "$SOURCE_REPO" worktree add --detach "$WORKTREE_DIR/repo" HEAD >/dev/null

  cleanup() {
    if [[ -n "$WORKTREE_DIR" && -d "$WORKTREE_DIR/repo" ]]; then
      cd /
      git -C "$SOURCE_REPO" worktree remove --force "$WORKTREE_DIR/repo" >/dev/null 2>&1 || true
      rm -rf "$WORKTREE_DIR"
    fi
  }
  trap cleanup EXIT

  REPO="$WORKTREE_DIR/repo"
  cd "$REPO"
elif [[ -n "$(git -C "$REPO" status --porcelain)" ]]; then
  warn "Repo has local git changes; use --clean-head to run without local modifications."
fi

run_platform_test() {
  local env_name="$1"
  local api_url api_key org_id

  if [[ "$env_name" == "staging" ]]; then
    api_url="https://staging.api.neuracore.com/api"
    api_key="${STAGING_NEURACORE_API_KEY:-}"
    org_id="${STAGING_NEURACORE_ORG_ID:-}"
  else
    api_url="https://api.neuracore.com/api"
    api_key="${PROD_NEURACORE_API_KEY:-}"
    org_id="${PROD_NEURACORE_ORG_ID:-}"
  fi

  if [[ -z "$api_key" || -z "$org_id" ]]; then
    warn "Skipping integration-platform (${env_name}): missing ${env_name^^}_NEURACORE_API_KEY or ${env_name^^}_NEURACORE_ORG_ID"
    return 0
  fi

  log "Integration Platform (${env_name}): installing deps"
  uv sync --locked --group dev --extra ml

  log "Integration Platform (${env_name}): running test"
  NEURACORE_API_URL="$api_url" \
  NEURACORE_API_KEY="$api_key" \
  NEURACORE_ORG_ID="$org_id" \
  uv run pytest -o log_cli=true --log-cli-level=INFO \
    tests/integration/test_consume_stream.py::test_get_latest_data_from_multiple_nodes
}

run_ml_test() {
  local env_name="$1"
  local api_url api_key org_id

  if [[ "$env_name" == "staging" ]]; then
    api_url="https://staging.api.neuracore.com/api"
    api_key="${STAGING_NEURACORE_API_KEY:-}"
    org_id="${STAGING_NEURACORE_ORG_ID:-}"
  else
    api_url="https://api.neuracore.com/api"
    api_key="${PROD_NEURACORE_API_KEY:-}"
    org_id="${PROD_NEURACORE_ORG_ID:-}"
  fi

  if [[ -z "$api_key" || -z "$org_id" ]]; then
    warn "Skipping integration-ml (${env_name}): missing ${env_name^^}_NEURACORE_API_KEY or ${env_name^^}_NEURACORE_ORG_ID"
    return 0
  fi

  if [[ "$INSTALL_ML_SYSTEM_DEPS" == "true" ]]; then
    log "Installing integration-ml system packages"
    sudo apt-get update
    sudo apt-get install -y libxml2-utils xvfb libgl1-mesa-dev libgl1-mesa-glx libosmesa6-dev
  fi

  log "Integration ML (${env_name}): installing deps"
  uv sync --locked --only-group dev
  if [[ "$env_name" == "production" ]]; then
    uv pip install "neuracore[ml,examples]"
  else
    uv pip install ".[ml,examples]"
  fi

  log "Integration ML (${env_name}): running test"
  local test_cmd=(uv run pytest -o log_cli=true --log-cli-level=INFO -v -n 8 tests/integration/test_algorithm.py)

  if command -v xvfb-run >/dev/null 2>&1; then
    NEURACORE_API_URL="$api_url" \
    NEURACORE_API_KEY="$api_key" \
    NEURACORE_ORG_ID="$org_id" \
    NEURACORE_ENDPOINT_TIMEOUT="30" \
    xvfb-run -a "${test_cmd[@]}"
  else
    warn "xvfb-run not found; running ML integration test without virtual display"
    NEURACORE_API_URL="$api_url" \
    NEURACORE_API_KEY="$api_key" \
    NEURACORE_ORG_ID="$org_id" \
    NEURACORE_ENDPOINT_TIMEOUT="30" \
    "${test_cmd[@]}"
  fi
}

log "0) Baseline checks"
uv --version
uv lock --check
uv build
uv version --short
uv version --short --bump patch --dry-run --frozen

log "1) PR pre-commit workflow parity"
uv sync --locked --group dev
uv run pre-commit run --all-files

log "2) PR unit test workflow parity"
uv sync --locked --group dev --extra ml --extra import
uv run pytest tests/unit --ignore=tests/unit/ml/algorithms/test_pi0.py
uv run pytest tests/unit/ml/algorithms/test_pi0.py

if [[ "$RUN_PLATFORM_STAGING" == "true" ]]; then
  run_platform_test "staging"
fi

if [[ "$RUN_PLATFORM_PRODUCTION" == "true" ]]; then
  run_platform_test "production"
fi

if [[ "$RUN_ML_STAGING" == "true" ]]; then
  run_ml_test "staging"
fi

if [[ "$RUN_ML_PRODUCTION" == "true" ]]; then
  run_ml_test "production"
fi

if [[ "$RUN_RELEASE_CHECKS" == "true" ]]; then
  log "Release workflow parity checks (dry-run)"
  uv lock --check
  uv version --short
  uv build

  if [[ -n "${PYPI_USERNAME:-}" && -n "${PYPI_PASSWORD:-}" ]]; then
    UV_PUBLISH_USERNAME="$PYPI_USERNAME" \
    UV_PUBLISH_PASSWORD="$PYPI_PASSWORD" \
    uv publish --dry-run --check-url https://pypi.org/simple --trusted-publishing never dist/*
  else
    uv publish --dry-run --check-url https://pypi.org/simple --trusted-publishing never dist/* || \
      warn "uv publish --dry-run failed without PyPI credentials; set PYPI_USERNAME/PYPI_PASSWORD if needed"
  fi

  log "Prepare-release parity checks"
  CURRENT_VERSION=$(uv version --short)
  echo "Current version: $CURRENT_VERSION"
  uv version --short --bump patch --dry-run --frozen
  uv version --short --bump minor --dry-run --frozen
  uv version --short --bump major --dry-run --frozen
fi

log "All requested checks completed"

@aditya-neuraco aditya-neuraco self-assigned this Jan 8, 2026
@aditya-neuraco aditya-neuraco added the version:none tests, docs, CI only; no functional changes label Jan 8, 2026
@stepjam stepjam requested a review from Copilot January 16, 2026 13:09
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates the project from traditional setuptools with setup.py to modern Python packaging using uv as the primary package manager and build tool. The migration simplifies dependency management, build processes, and CI/CD workflows while maintaining backward compatibility.

Changes:

  • Replaced setup.py with pyproject.toml using hatchling as the build backend
  • Migrated all GitHub Actions workflows to use uv for dependency installation, testing, and publishing
  • Updated version management to use uv version command and dynamic version loading via importlib.metadata
  • Enhanced algorithm_loader.py to prefer uv pip over pip when available

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
setup.py Removed legacy setuptools-based configuration file
pyproject.toml Added modern PEP 621 compliant project configuration with uv-specific settings
neuracore/init.py Updated to use dynamic version loading from package metadata
neuracore/ml/utils/algorithm_loader.py Enhanced to prefer uv pip when available with graceful pip fallback
.bumpversion.cfg Removed in favor of uv's built-in version management
.github/workflows/*.yaml Updated all CI/CD workflows to use astral-sh/setup-uv@v5 and uv commands
README.md Added uv installation instructions and updated development/testing commands
cSpell.json Added pyproject.toml and uv.lock to ignore list
neuracore-dictionary.txt Added "venv" to custom dictionary

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@stepjam stepjam changed the base branch from main to develop February 7, 2026 13:51
@stepjam stepjam deleted the branch develop February 7, 2026 14:02
@stepjam stepjam closed this Feb 7, 2026
@stepjam stepjam reopened this Feb 7, 2026
@aditya-neuraco aditya-neuraco force-pushed the refactor/migrate-everything-to-uv branch from b71054f to 67a232f Compare February 11, 2026 13:14
@aditya-neuraco aditya-neuraco force-pushed the refactor/migrate-everything-to-uv branch from 380be02 to 8acf12b Compare February 12, 2026 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

version:none tests, docs, CI only; no functional changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants