Skip to content
Open
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
8 changes: 4 additions & 4 deletions OneBranchPipelines/build-release-package-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,8 @@ extends:
# 1. Installs Python (UsePythonVersion or NuGet for 3.14)
# 2. Downloads ARM64 python.lib if cross-compiling
# 3. Builds .pyd native extension
# 4. Runs pytest (x64 only, ARM64 can't execute on x64 host)
# 5. Builds wheel
# 4. Builds wheel
# 5. Installs and tests the wheel outside the checkout (x64 only)
# 6. Publishes artifacts (wheels + PYD + PDB)
# 7. ESRP malware scanning
- ${{ each config in parameters.windowsConfigs }}:
Expand Down Expand Up @@ -423,8 +423,8 @@ extends:
# 2. Installs CMake and pybind11
# 3. Builds universal2 .so (ARCHFLAGS="-arch x86_64 -arch arm64")
# 4. Starts SQL Server Docker container (via Colima)
# 5. Runs pytest
# 6. Builds wheel
# 5. Builds and retags the universal2 wheel
# 6. Installs and tests the wheel outside the checkout
# 7. Publishes artifacts (wheels + .so)
# 8. ESRP malware scanning
- ${{ each config in parameters.macosConfigs }}:
Expand Down
59 changes: 29 additions & 30 deletions OneBranchPipelines/stages/build-macos-single-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,43 +221,42 @@ stages:
displayName: 'Install external ODBC wheel (mssql-python-odbc)'

# =========================
# TESTING
# WHEEL BUILD AND TESTING
# =========================
# Run pytest against SQL Server container
# Tests use localhost:1433 connection (SA user with password from variable)
# -v = verbose output (show test names and results)
- script: |
python -m pytest -v
displayName: 'Run pytests'
env:
# Connection string uses localhost (SQL Server container exposed on port 1433)
# TrustServerCertificate=yes bypasses SSL cert validation (test env only)
DB_CONNECTION_STRING: 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes'

# =========================
# WHEEL BUILD
# =========================

# Build wheel package from setup.py
# Wheel filename: mssql_python-X.Y.Z-cp3XX-cp3XX-macosx_XX_X_universal2.whl
# bdist_wheel = build binary wheel distribution (contains pre-compiled .so)
# Build and retag the final wheel, then install and test it from a
# directory that cannot resolve mssql_python from the source checkout.
- script: |
set -euo pipefail
cd "$(Build.SourcesDirectory)"
python -m pip install --upgrade pip wheel setuptools
python setup.py bdist_wheel
displayName: 'Build wheel package'

# Retag wheel to universal2 — the .so binary is already universal2 (CMake cross-compiles
# both arm64 + x86_64), but bdist_wheel may tag as x86_64 when the Python interpreter
# lacks universal2 support (e.g. Python 3.10 from UsePythonVersion@0 is x86_64-only).
# Same approach used in mssql-tds Rust pipeline (build-python-wheels-template.yml).
- script: |
for whl in dist/*.whl; do
echo "Retagging: $(basename $whl)"
echo "Retagging: $(basename "$whl")"
wheel tags --platform-tag macosx_15_0_universal2 --remove "$whl"
done
echo "Wheels after retag:"
ls -lh dist/
displayName: 'Ensure universal2 platform tag'

TEST_DIR="$(Agent.TempDirectory)/mssql-python-wheel-test"
WHEEL=$(find "$(Build.SourcesDirectory)/dist" -maxdepth 1 -name '*.whl' -print -quit)
if [ -z "$WHEEL" ]; then
echo "No wheel found in dist/" >&2
exit 1
fi

python -m pip install --force-reinstall --no-deps "$WHEEL"
rm -rf "$TEST_DIR"
mkdir -p "$TEST_DIR"
cp -R "$(Build.SourcesDirectory)/tests" "$TEST_DIR/tests"
cp -R "$(Build.SourcesDirectory)/.github" "$TEST_DIR/.github"
cp "$(Build.SourcesDirectory)/pytest.ini" "$TEST_DIR/pytest.ini"

cd "$TEST_DIR"
python -c "import os,mssql_python as m; p=os.path.realpath(os.path.dirname(m.__file__)); s=os.path.realpath(os.environ['BUILD_SOURCESDIRECTORY']); assert not p.startswith(s), 'mssql_python resolved inside checkout: '+p; print('mssql_python resolved from installed wheel:', p)"
python -m pytest tests -v
displayName: 'Build and test wheel'
env:
# Connection string uses localhost (SQL Server container exposed on port 1433)
# TrustServerCertificate=yes bypasses SSL cert validation (test env only)
DB_CONNECTION_STRING: 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes'

# =========================
# ARTIFACT PUBLISHING
Expand Down
57 changes: 41 additions & 16 deletions OneBranchPipelines/stages/build-windows-single-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -343,18 +343,51 @@ stages:
condition: ne(variables['targetArch'], 'arm64')

# =========================
# TESTING
# WHEEL BUILD AND TESTING
# =========================
# Run pytest to validate bindings (x64 only)
# ARM64 binaries cannot execute on x64 host, so tests are skipped
# Build the signed wheel for every architecture. Install and test x64
# wheels from a directory that cannot resolve mssql_python from the
# source checkout. ARM64 wheels cannot execute on the x64 build host.
- powershell: |
Write-Host "Running pytests to validate bindings"
$ErrorActionPreference = "Stop"
Set-Location "$(Build.SourcesDirectory)"
python -m pip install --upgrade pip wheel setuptools
if ($LASTEXITCODE -ne 0) { throw "Failed to install wheel build dependencies" }
$env:ARCHITECTURE = "$(targetArch)"
python setup.py bdist_wheel
if ($LASTEXITCODE -ne 0) { throw "Failed to build wheel" }

if ("$(targetArch)" -eq "arm64") {
Write-Host "Skipping pytests on Windows ARM64"
} else {
python -m pytest -v
Write-Host "Skipping wheel tests on Windows ARM64"
exit 0
}

$wheels = @(Get-ChildItem "$(Build.SourcesDirectory)\dist" -Filter *.whl -File)
if ($wheels.Count -ne 1) {
Write-Error "Expected one wheel in dist\, found $($wheels.Count)"
exit 1
}
displayName: 'Run pytests'

python -m pip install --force-reinstall --no-deps "$($wheels[0].FullName)"
if ($LASTEXITCODE -ne 0) { throw "Failed to install built wheel" }

$testDir = Join-Path "$(Agent.TempDirectory)" "mssql-python-wheel-test"
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $testDir
New-Item -ItemType Directory -Force -Path $testDir | Out-Null
Copy-Item "$(Build.SourcesDirectory)\tests" "$testDir\tests" -Recurse
Copy-Item "$(Build.SourcesDirectory)\.github" "$testDir\.github" -Recurse
Copy-Item "$(Build.SourcesDirectory)\pytest.ini" "$testDir\pytest.ini"

Push-Location $testDir
try {
python -c "import os,mssql_python as m; p=os.path.realpath(os.path.dirname(m.__file__)); s=os.path.realpath(os.environ['BUILD_SOURCESDIRECTORY']); assert not p.startswith(s), 'mssql_python resolved inside checkout: '+p; print('mssql_python resolved from installed wheel:', p)"
if ($LASTEXITCODE -ne 0) { throw "Built wheel did not import outside the checkout" }
python -m pytest tests -v
if ($LASTEXITCODE -ne 0) { throw "Wheel tests failed" }
} finally {
Pop-Location
}
displayName: 'Build and test wheel'
env:
DB_CONNECTION_STRING: 'Server=(localdb)\MSSQLLocalDB;Database=TestDB;Uid=testuser;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes'

Expand Down Expand Up @@ -391,14 +424,6 @@ stages:
TargetFolder: '$(Build.SourcesDirectory)\apiScan\pdbs\windows\py$(shortPyVer)\$(targetArch)'
displayName: 'Copy PDB to ApiScan directory'

# Build Python wheel package from source distribution
# ARCHITECTURE environment variable controls target platform tagging
- script: |
python -m pip install --upgrade pip wheel setuptools
set ARCHITECTURE=$(targetArch)
python setup.py bdist_wheel
displayName: 'Build wheel package'

# =========================
# SIGNED-WHEEL EVIDENCE (verification only)
# =========================
Expand Down
2 changes: 2 additions & 0 deletions tests/test_004_cursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@
def test_package_sources_compile_with_warnings_as_errors():
"""Every package source must compile when warnings are promoted to errors."""
package_dir = Path(__file__).parents[1] / "mssql_python"
if not package_dir.is_dir():
pytest.skip("requires a source checkout")
for source in sorted(package_dir.glob("*.py")):
with warnings.catch_warnings():
warnings.simplefilter("error")
Expand Down
16 changes: 10 additions & 6 deletions tests/test_025_odbc_package_required.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,26 @@
the actionable guidance surfaced by ``connect()``.
"""

import glob
import os
import subprocess
import sys
from importlib.util import find_spec
from pathlib import Path

import pytest

_REPO_ROOT = Path(__file__).resolve().parent.parent
_MSSQL_DIR = _REPO_ROOT / "mssql_python"
_PACKAGE_SPEC = find_spec("mssql_python")
_MSSQL_DIR = (
Path(next(iter(_PACKAGE_SPEC.submodule_search_locations))).resolve()
if _PACKAGE_SPEC and _PACKAGE_SPEC.submodule_search_locations
else _REPO_ROOT / "mssql_python"
)

# These tests drive the *native* resolver, so they require the compiled
# extension. Skip cleanly in a source-only checkout where it was never built.
_EXT_BUILT = bool(
glob.glob(str(_MSSQL_DIR / "ddbc_bindings.*.pyd"))
or glob.glob(str(_MSSQL_DIR / "ddbc_bindings.*.so"))
# extension from either the checkout or the installed wheel.
_EXT_BUILT = any(_MSSQL_DIR.glob("ddbc_bindings.*.pyd")) or any(
_MSSQL_DIR.glob("ddbc_bindings.*.so")
)
pytestmark = pytest.mark.skipif(not _EXT_BUILT, reason="native ddbc_bindings extension not built")

Expand Down
Loading