From 499f3a2a07bf15312890d53c511f20c1c13f06e5 Mon Sep 17 00:00:00 2001 From: Xinyi Joffre Date: Thu, 2 Oct 2025 23:41:28 -0700 Subject: [PATCH 1/5] Migrate to use venv --- .ado/ci.yml | 2 +- .ado/publish.yml | 2 +- azure-quantum/MANIFEST.in | 1 - azure-quantum/README.md | 41 ++++ azure-quantum/eng/Record-Tests.ps1 | 9 +- azure-quantum/eng/Setup-Dev-Env.ps1 | 27 ++- azure-quantum/environment.yml | 11 - azure-quantum/requirements-dev.txt | 2 + .../tests.live/Install-Artifacts.ps1 | 19 +- azure-quantum/tests.live/Run.ps1 | 16 +- azure-quantum/tests/README.md | 14 +- build/conda-utils.psm1 | 142 ------------- build/package-utils.psm1 | 200 +++++------------- build/venv-utils.psm1 | 126 +++++++++++ 14 files changed, 283 insertions(+), 329 deletions(-) delete mode 100644 azure-quantum/environment.yml delete mode 100644 build/conda-utils.psm1 create mode 100644 build/venv-utils.psm1 diff --git a/.ado/ci.yml b/.ado/ci.yml index d2205e029..f063bd252 100644 --- a/.ado/ci.yml +++ b/.ado/ci.yml @@ -67,7 +67,7 @@ jobs: - script: | cd $(Build.SourcesDirectory)/azure-quantum - pip install .[all] + pip install .[qiskit,cirq,qsharp,dev] pytest --cov-report term --cov=azure.quantum --junitxml test-output-azure-quantum.xml $(Build.SourcesDirectory)/azure-quantum displayName: Run azure-quantum unit tests diff --git a/.ado/publish.yml b/.ado/publish.yml index fd6f6338f..e77d77b79 100644 --- a/.ado/publish.yml +++ b/.ado/publish.yml @@ -117,7 +117,7 @@ extends: - script: | cd $(Build.SourcesDirectory)/azure-quantum - pip install .[all] + pip install .[qiskit,cirq,qsharp,dev] pytest --cov-report term --cov=azure.quantum --junitxml test-output-azure-quantum.xml $(Build.SourcesDirectory)/azure-quantum displayName: Run Unit-tests diff --git a/azure-quantum/MANIFEST.in b/azure-quantum/MANIFEST.in index 4baebbfe3..879ba3554 100644 --- a/azure-quantum/MANIFEST.in +++ b/azure-quantum/MANIFEST.in @@ -3,7 +3,6 @@ include *.py include *.md recursive-include azure *.py exclude MANIFEST.in -exclude environment.yml recursive-exclude azure *.typed recursive-exclude eng * recursive-exclude tests * diff --git a/azure-quantum/README.md b/azure-quantum/README.md index 143167bfb..c269a424e 100644 --- a/azure-quantum/README.md +++ b/azure-quantum/README.md @@ -79,6 +79,47 @@ result = job.get_results() You can find example Python scripts that use the Azure Quantum Python API in the [examples](https://github.com/microsoft/qdk-python/tree/main/azure-quantum/examples) directory. +## Development Setup ## + +For developers who want to contribute to this package or run tests locally, follow these steps: + +### Prerequisites + +- Python 3.9 or later +- Git + +### Setting up the development environment + +1. Clone the repository: + ```bash + git clone https://github.com/microsoft/qdk-python.git + cd qdk-python/azure-quantum + ``` + +2. Set up a virtual environment and install development dependencies: + ```powershell + # On Windows (PowerShell) + .\eng\Setup-Dev-Env.ps1 + ``` + +3. Run the tests: + ```bash + pytest tests/unit/ + ``` + +4. (Optional) Install additional provider dependencies: + ```bash + # For specific providers + pip install -e .[pulser,quil] + + # For all providers (requires Rust toolchain for PyQuil) + pip install -e .[all] + ``` + +### Running Tests + +The development environment includes pytest for running unit tests. See [tests/README.md](tests/README.md) for detailed testing instructions. + ## Contributing ## For details on contributing to this package, see the [contributing guide](https://github.com/microsoft/qdk-python/blob/main/CONTRIBUTING.md). diff --git a/azure-quantum/eng/Record-Tests.ps1 b/azure-quantum/eng/Record-Tests.ps1 index 238dcff41..7fd31d2bf 100644 --- a/azure-quantum/eng/Record-Tests.ps1 +++ b/azure-quantum/eng/Record-Tests.ps1 @@ -20,7 +20,14 @@ try { Push-Location (Join-Path $PSScriptRoot "../tests/") - conda activate azurequantum + # Activate virtual environment if it exists + $VenvPath = "../venv" + if (Test-Path $VenvPath) { + Write-Host "Activating virtual environment..." + & "$VenvPath\Scripts\Activate.ps1" + } else { + Write-Warning "Virtual environment not found at $VenvPath. Please run Setup-Dev-Env.ps1 first." + } if ([string]::IsNullOrEmpty($TestFilter)) { pytest diff --git a/azure-quantum/eng/Setup-Dev-Env.ps1 b/azure-quantum/eng/Setup-Dev-Env.ps1 index 918d95a58..d2b2d268d 100644 --- a/azure-quantum/eng/Setup-Dev-Env.ps1 +++ b/azure-quantum/eng/Setup-Dev-Env.ps1 @@ -7,11 +7,30 @@ try { Push-Location (Join-Path $PSScriptRoot "../") - conda env create -f environment.yml - conda env update -f environment.yml --prune - conda activate azurequantum + # Create virtual environment if it doesn't exist + $VenvPath = "venv" + if (-not (Test-Path $VenvPath)) { + Write-Host "Creating virtual environment..." + python -m venv $VenvPath + } - pip install -e .[qiskit,cirq] + # Activate virtual environment + Write-Host "Activating virtual environment..." + & ".\$VenvPath\Scripts\Activate.ps1" + + # Upgrade pip and install build tools + Write-Host "Upgrading pip and installing build tools..." + python -m pip install --upgrade pip setuptools wheel + + # Install package in editable mode with optional dependencies + Write-Host "Installing package in editable mode..." + pip install -e .[qiskit,cirq,qsharp,dev] + + Write-Host "" + Write-Host "Development environment setup complete!" + Write-Host "To install additional optional dependencies later, run:" + Write-Host " pip install -e .[pulser,quil] # for specific providers" + Write-Host " pip install -e .[all] # for all providers (requires Rust toolchain)" } finally { diff --git a/azure-quantum/environment.yml b/azure-quantum/environment.yml deleted file mode 100644 index 5942f90e4..000000000 --- a/azure-quantum/environment.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: azurequantum -channels: - - quantum-engineering - - conda-forge -dependencies: - - python=3.9 - - pip>=22.3.1 - - pytest>=7.1.2 - - pytest-regressions - - pip: - - -e .[all] diff --git a/azure-quantum/requirements-dev.txt b/azure-quantum/requirements-dev.txt index 6a92c4ebc..db72c8fcc 100644 --- a/azure-quantum/requirements-dev.txt +++ b/azure-quantum/requirements-dev.txt @@ -1,3 +1,5 @@ +pytest>=7.1.2 +pytest-regressions vcrpy>=4.3.1 # fixes https://github.com/kevin1024/vcrpy/issues/688 azure-devtools>=1.2.0,<2.0 graphviz>=0.20.1 \ No newline at end of file diff --git a/azure-quantum/tests.live/Install-Artifacts.ps1 b/azure-quantum/tests.live/Install-Artifacts.ps1 index e07717c72..c22895919 100644 --- a/azure-quantum/tests.live/Install-Artifacts.ps1 +++ b/azure-quantum/tests.live/Install-Artifacts.ps1 @@ -3,19 +3,19 @@ <# .SYNOPSIS - Install-Artifacts: set up a Python environment using Anaconda + Install-Artifacts: set up a Python environment using virtual environments #> $PackageDir = Split-Path -parent $PSScriptRoot; $PackageName = $PackageDir | Split-Path -Leaf; $RootDir = Split-Path -parent $PackageDir; -Import-Module (Join-Path $RootDir "build" "conda-utils.psm1"); +Import-Module (Join-Path $RootDir "build" "venv-utils.psm1"); Import-Module (Join-Path $RootDir "build" "package-utils.psm1"); -# Enable conda hook -Enable-Conda +# Enable venv support +Enable-Venv -NewCondaEnvForPackage -PackageName $PackageName +New-VenvForPackage -PackageName $PackageName if (-not $Env:PYTHON_OUTDIR) { "" | Write-Host @@ -23,7 +23,7 @@ if (-not $Env:PYTHON_OUTDIR) { "== We will install $PackageName from source." | Write-Host "" | Write-Host - Install-PackageInEnv -PackageName "$PackageName[all]" -FromSource $True + Install-PackageInEnv -PackageName "$PackageName[qiskit,cirq,qsharp,dev]" -FromSource $True "" | Write-Host "== $PackageName installed from source. ==" | Write-Host @@ -34,7 +34,8 @@ if (-not $Env:PYTHON_OUTDIR) { "== To use build artifacts, download the artifacts locally and point the variable to this folder." | Write-Warning "" | Write-Warning Exit 1 -} +} + # this condition is used by the E2E Live test pipeline elseif ($Env:PICK_QDK_VERSION -eq "auto") { "== Installing latest published $PackageName package from PyPI..." | Write-Host @@ -43,9 +44,9 @@ elseif ($Env:PICK_QDK_VERSION -eq "auto") { "== Preparing environment to use artifacts with version '$Env:PYTHON_VERSION' " | Write-Host "== from '$Env:PYTHON_OUTDIR'" | Write-Host if ($Env:PYTHON_VERSION) { - $NameAndVersion = "$PackageName[all]==$($Env:PYTHON_VERSION)" + $NameAndVersion = "$PackageName[qiskit,cirq,qsharp,dev]==$($Env:PYTHON_VERSION)" } else { - $NameAndVersion = "$PackageName[all]" + $NameAndVersion = "$PackageName[qiskit,cirq,qsharp,dev]" } Install-PackageInEnv -PackageName $NameAndVersion -FromSource $False -BuildArtifactPath $Env:PYTHON_OUTDIR diff --git a/azure-quantum/tests.live/Run.ps1 b/azure-quantum/tests.live/Run.ps1 index ef9340f94..c5ec64332 100644 --- a/azure-quantum/tests.live/Run.ps1 +++ b/azure-quantum/tests.live/Run.ps1 @@ -18,7 +18,7 @@ Get-ChildItem env:AZURE*, env:*VERSION, env:*OUTDIR | ForEach-Object { $PackageDir = Split-Path -parent $PSScriptRoot; $PackageName = $PackageDir | Split-Path -Leaf; $RootDir = Split-Path -parent $PackageDir; -Import-Module (Join-Path $RootDir "build" "conda-utils.psm1"); +Import-Module (Join-Path $RootDir "build" "venv-utils.psm1"); Import-Module (Join-Path $RootDir "build" "package-utils.psm1"); if ($True -eq $SkipInstall) { @@ -27,23 +27,23 @@ if ($True -eq $SkipInstall) { & (Join-Path $PSScriptRoot Install-Artifacts.ps1) } -Enable-Conda +Enable-Venv -# Try activating the azurequantum conda environment +# Try activating the virtual environment for azure-quantum if ([string]::IsNullOrEmpty($PackageName) -or ($PackageName -eq "azure-quantum")) { try { - $EnvExists = conda env list | Select-String -Pattern "azurequantum " | Measure-Object | Select-Object -Exp Count - if ($EnvExists) { - conda activate azurequantum + $VenvPath = Join-Path (Split-Path -parent $PSScriptRoot) "venv" + if (Test-Path $VenvPath) { + Use-Venv -VenvName "venv" } } catch { - Write-Host "##[warning]Failed to active conda environment." + Write-Host "##[warning]Failed to activate virtual environment." } } $EnvName = GetEnvName -PackageName $PackageName -Use-CondaEnv $EnvName +Use-Venv -VenvName $EnvName function PyTestMarkExpr() { param ( diff --git a/azure-quantum/tests/README.md b/azure-quantum/tests/README.md index 482fc3af2..246619dc3 100644 --- a/azure-quantum/tests/README.md +++ b/azure-quantum/tests/README.md @@ -2,7 +2,19 @@ ## Environment Pre-reqs -Refer to [the parent README](../README.md) for how to prepare the development environment before running the unit tests. +Before running the unit tests, set up your development environment using the venv-based setup: + +### On Windows (PowerShell): +```powershell +.\eng\Setup-Dev-Env.ps1 +``` + +This will install the package with common optional dependencies (qiskit, cirq, qsharp). To install additional provider dependencies, run: +```bash +source venv/bin/activate # Activate the virtual environment first +pip install -e .[pulser,quil] # for specific providers +pip install -e .[all] # for all providers (requires Rust toolchain) +``` ### Environment variables for Recording and Live-Tests diff --git a/build/conda-utils.psm1 b/build/conda-utils.psm1 deleted file mode 100644 index 6f56c7995..000000000 --- a/build/conda-utils.psm1 +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -<# - .SYNOPSIS - Includes utility cmdlets for working with conda both locally, - and in Azure Pipelines and other hosted environments. -#> - -function Test-CondaEnabled { - <# - .SYNOPSIS - Tests if conda has been enabled for shell - use (e.g.: if conda activate will work). - #> - - # The shell hook for conda creates a new cmdlet called - # Invoke-Conda that is then aliased to `conda`. If the - # full name (without an alias) is available, then the hook - # has been run already. - if ($null -ne (Get-Command Invoke-Conda -ErrorAction SilentlyContinue)) { - return $true; - } - return $false; -} - -function Enable-Conda { - <# - .SYNOPSIS - Attempts to enable conda for shell usage, first using - the CONDA environment variable for the path, falling back - to PATH, and then failing. - If conda is already enabled, this cmdlet does nothing, - so that this cmdlet is idempotent. - #> - - if (Test-CondaEnabled) { return $true; } - - if ("$Env:CONDA" -ne "") { - # Try and run the shell hook from the path nominated - # by CONDA. - - # On Windows, this is $Env:CONDA/Scripts/conda.exe, while on - # Linux and macOS, this is $Env:CONDA/bin/conda. - - if ($IsWindows) { - $condaBin = Join-Path $Env:CONDA "Scripts" "conda.exe"; - } else { - $condaBin = Join-Path $Env:CONDA "bin" "conda"; - } - - if ($null -eq (Get-Command $condaBin -ErrorAction SilentlyContinue)) { - Write-Error "##[error] conda binary was expected at $condaBin (CONDA = $Env:CONDA), but was not found."; - throw; - } - - (& $condaBin shell.powershell hook) | Out-String | Invoke-Expression; - } else { - (conda shell.powershell hook) | Out-String | Invoke-Expression; - } -} - -function Use-CondaEnv { - param ( - [string] $EnvName - ) - <# - .SYNOPSIS - Activates a conda environment, reporting the new configuration - after having done so. If conda has not already been enabled, this - cmdlet will enable it before activating. - #> - - Enable-Conda - # NB: We use the PowerShell cmdlet created by the conda shell hook here - # to avoid accidentally using the conda binary. - Enter-CondaEnvironment $EnvName - Write-Host "##[info]Activated Conda env: $(Get-PythonConfiguration | Out-String)" -} - -function Install-Package() { - param( - [string] $EnvName, - [string] $PackageName, - [bool] $FromSource - ) - # Activate env - Use-CondaEnv $EnvName - # Install package - if ($True -eq $FromSource) { - $ParentPath = Split-Path -parent $PSScriptRoot - $AbsPackageDir = Join-Path $ParentPath $PackageName - Write-Host "##[info]Install package $AbsPackageDir in development mode for env $EnvName" - pip install -e $AbsPackageDir - } else { - Write-Host "##[info]Install package $PackageName for env $EnvName" - pip install $PackageName - } -} - -function Get-PythonConfiguration { - <# - .SYNOPSIS - Returns a table describing the current Python configuration, - useful for diagnostic purposes. - #> - - $table = @{}; - - $python = (Get-Command python -ErrorAction SilentlyContinue); - if ($null -ne $python) { - $table["PythonLocation"] = $python.Source; - try { - $table["PythonVersion"] = & $python --version; - } catch { } - } - - # If the CONDA environment variable is set, allow that to override - # the local PATH. - $conda = Get-Command conda -ErrorAction SilentlyContinue; - - if ($null -ne $conda) { - $table["CondaLocation"] = $conda.Source; - try { - $table["CondaVersion"] = & $conda --version; - } catch { } - } - - # If the conda hook has already been run, we can get some additional - # information for the table. - if (Test-CondaEnabled) { - try { - $env = Get-CondaEnvironment | Where-Object -Property Active; - if ($null -ne $env) { - $table["CondaEnvName"] = $env.Name; - $table["CondaEnvPath"] = $env.Path; - } - } catch { } - } - - $table | Write-Output; -} \ No newline at end of file diff --git a/build/package-utils.psm1 b/build/package-utils.psm1 index 0e96889e6..7195e67bb 100644 --- a/build/package-utils.psm1 +++ b/build/package-utils.psm1 @@ -1,168 +1,68 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. -Import-Module (Join-Path $PSScriptRoot "conda-utils.psm1"); +<# + .SYNOPSIS + PowerShell utilities for package management +#> -function PackagesList{ - param( - [string] $PackageName - ) - if ('' -eq $PackageName) { - # If no package dir is specified, find all packages that contain an environment.yml file - $parentPath = Split-Path -parent $PSScriptRoot - $PackageNames = Get-ChildItem -Path $parentPath -Recurse -Filter "environment.yml" | Select-Object -ExpandProperty Directory | Split-Path -Leaf - Write-Host "##[info]No PackageDir. Setting to default '$PackageNames'" - } else { - $PackageNames = @($PackageName) - } - return $PackageNames -} - -function Install-Package() { +function Install-PackageInEnv { + <# + .SYNOPSIS + Install a package in the current environment + .PARAMETER PackageName + The name of the package to install + .PARAMETER FromSource + Whether to install from source (editable install) + .PARAMETER BuildArtifactPath + Path to build artifacts (optional) + #> param( - [string] $EnvName, + [Parameter(Mandatory=$true)] [string] $PackageName, - [bool] $FromSource, - [string] $BuildArtifactPath + + [Parameter(Mandatory=$false)] + [bool] $FromSource = $false, + + [Parameter(Mandatory=$false)] + [string] $BuildArtifactPath = "" ) - # Activate env - Use-CondaEnv $EnvName - # Show all installed packages - conda list - # Install package - if ($True -eq $FromSource) { - $ParentPath = Split-Path -parent $PSScriptRoot - $AbsPackageName = Join-Path $ParentPath $PackageName - Write-Host "##[info]Install package $AbsPackageName in development mode for env $EnvName" - pip install -e $AbsPackageName - } elseif ("" -ne $BuildArtifactPath) { - Write-Host "##[info]Installing $PackageName from $BuildArtifactPath" - Push-Location $BuildArtifactPath - pip install $PackageName --pre --find-links $BuildArtifactPath - if ($LASTEXITCODE -ne 0) { throw "Error installing qsharp-core wheel" } - Pop-Location + + if ($FromSource) { + Write-Host "Installing '$PackageName' from source (editable install)..." + pip install -e "[$PackageName]" + } elseif (-not [string]::IsNullOrEmpty($BuildArtifactPath)) { + Write-Host "Installing '$PackageName' from build artifacts at '$BuildArtifactPath'..." + $WheelFiles = Get-ChildItem -Path $BuildArtifactPath -Filter "*.whl" + if ($WheelFiles.Count -gt 0) { + pip install $WheelFiles[0].FullName + } else { + Write-Warning "No wheel files found in '$BuildArtifactPath'. Installing from PyPI instead." + pip install $PackageName + } } else { - Write-Host "##[info]Install latest package $PackageName for env $EnvName from PyPI" + Write-Host "Installing '$PackageName' from PyPI..." pip install $PackageName } } function GetEnvName { - param ( - [string] $PackageName, - [string] $CondaEnvironmentSuffix - ) - # The environment name is based on $PackageName, but - # 1. if the name includes the version via name==version, remove the version, - # 2. add conda env suffix - # 3. remove "-" since its invalid - # 4. remove ".aio" and use the same environment as the non-async version - return ($PackageName.Split("[")[0].Split("=")[0] + $CondaEnvironmentSuffix).replace("-", "").replace(".aio", "") -} - -function Install-PackageInEnv { - param ( - [string] $PackageName, - [string] $CondaEnvironmentSuffix, - [bool] $FromSource, - [string] $BuildArtifactPath - ) - $PackageNames = PackagesList -PackageName $PackageName - foreach ($PackageName in $PackageNames) { - $EnvName = GetEnvName -PackageName $PackageName -CondaEnvironmentSuffix $CondaEnvironmentSuffix - Install-Package -EnvName $EnvName -PackageName $PackageName -FromSource $FromSource -BuildArtifactPath $BuildArtifactPath - } -} - -function New-CondaEnvironment { - param( - [string] $PackageName, - [string] $CondaEnvironmentSuffix - ) <# - .SYNOPSIS - Create Conda environment(s) for given package directories - Optionally, use CondaEnvironmentSuffix to specify a special environment file with name environment.yml. - If PackageName is not specified, get all packages in the root directory. + .SYNOPSIS + Get the environment name for a package + .PARAMETER PackageName + The name of the package #> - - $PackageNames = PackagesList -PackageName $PackageName - foreach ($PackageName in $PackageNames) { - NewCondaEnvForPackage -PackageName $PackageName -CondaEnvironmentSuffix $CondaEnvironmentSuffix - } -} - -function NewCondaEnvForPackage { param( - [string] $PackageName, - [string] $CondaEnvironmentSuffix + [Parameter(Mandatory=$true)] + [string] $PackageName ) - <# - .SYNOPSIS - Create Conda environment(s) for given package directories - Optionally, use CondaEnvironmentSuffix to specify a special environment file with name environment.yml. - #> - - $parentPath = Split-Path -parent $PSScriptRoot - $EnvPath = Join-Path $parentPath $PackageName "environment$CondaEnvironmentSuffix.yml" - $EnvName = GetEnvName -PackageName $PackageName -CondaEnvironmentSuffix $CondaEnvironmentSuffix - - # Check if environment already exists - $EnvExists = conda env list | Select-String -Pattern "$EnvName " | Measure-Object | Select-Object -Exp Count - - # If it exists, skip creation - if ($EnvExists -eq "1") { - Write-Host "##[info]Skipping creating $EnvName; env already exists." - - } else { - # If it does not exist, create conda environment - Write-Host "##[info]Build '$EnvPath' for Conda environment $EnvName" - conda env create --quiet --file $EnvPath + + if ([string]::IsNullOrEmpty($PackageName) -or ($PackageName -eq "azure-quantum")) { + return "venv" } + return "venv-$PackageName" } -function New-Wheel() { - param( - [string] $EnvName, - [string] $Path, - [string] $OutDir - ); - - Push-Location $Path - # Set environment vars to be able to run conda activate - Write-Host "##[info]Pack wheel for env '$EnvName'" - # Activate env - Use-CondaEnv $EnvName - # Create package distribution - python setup.py bdist_wheel sdist --formats=gztar - - if ($LastExitCode -ne 0) { - Write-Host "##vso[task.logissue type=error;]Failed to build $Path." - $script:all_ok = $False - } else { - if ($OutDir -ne "") { - Write-Host "##[info]Copying wheel to '$OutDir'" - Copy-Item "dist/*.whl" $OutDir/ - Copy-Item "dist/*.tar.gz" $OutDir/ - } - } - Pop-Location -} - - -function Invoke-Tests() { - param( - [string] $PackageName, - [string] $EnvName - ) - $ParentPath = Split-Path -parent $PSScriptRoot - $AbsPackageDir = Join-Path $ParentPath $PackageName - "##[info]Test package $AbsPackageDir and run tests for env $EnvName" | Write-Host - # Activate env - Use-CondaEnv $EnvName | Write-Host - # Install testing deps - python -m pip install --upgrade pip | Write-Host - pip install pytest pytest-azurepipelines pytest-cov | Write-Host - # Run tests - $PkgName = $PackageName.replace("-", ".") - pytest --cov-report term --cov=$PkgName --junitxml test-output-$PackageName.xml $AbsPackageDir | Write-Host - return ($LASTEXITCODE -eq 0) -} \ No newline at end of file +# Export functions +Export-ModuleMember -Function Install-PackageInEnv, GetEnvName \ No newline at end of file diff --git a/build/venv-utils.psm1 b/build/venv-utils.psm1 new file mode 100644 index 000000000..2a4c858e8 --- /dev/null +++ b/build/venv-utils.psm1 @@ -0,0 +1,126 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# + .SYNOPSIS + PowerShell utilities for managing Python virtual environments +#> + +function Enable-Venv { + <# + .SYNOPSIS + Initialize Python virtual environment support in the current session + #> + # Check if Python is available + try { + $PythonVersion = python --version 2>&1 + Write-Host "Using Python: $PythonVersion" + } + catch { + Write-Error "Python is not available in PATH. Please install Python first." + throw + } +} + +function Get-VenvName { + <# + .SYNOPSIS + Get the virtual environment name for a package + .PARAMETER PackageName + The name of the package + #> + param( + [Parameter(Mandatory=$true)] + [string] $PackageName + ) + + if ([string]::IsNullOrEmpty($PackageName) -or ($PackageName -eq "azure-quantum")) { + return "venv" + } + return "venv-$PackageName" +} + +function New-VenvForPackage { + <# + .SYNOPSIS + Create a new virtual environment for the specified package + .PARAMETER PackageName + The name of the package + #> + param( + [Parameter(Mandatory=$true)] + [string] $PackageName + ) + + $VenvName = Get-VenvName -PackageName $PackageName + $VenvPath = Join-Path (Get-Location) $VenvName + + Write-Host "Creating virtual environment '$VenvName' at '$VenvPath'..." + + # Create virtual environment if it doesn't exist + if (-not (Test-Path $VenvPath)) { + python -m venv $VenvPath + Write-Host "Virtual environment '$VenvName' created successfully." + } else { + Write-Host "Virtual environment '$VenvName' already exists." + } + + # Activate the environment + Use-Venv -VenvName $VenvName + + # Upgrade pip + Write-Host "Upgrading pip..." + python -m pip install --upgrade pip setuptools wheel +} + +function Use-Venv { + <# + .SYNOPSIS + Activate the specified virtual environment + .PARAMETER VenvName + The name of the virtual environment to activate + #> + param( + [Parameter(Mandatory=$true)] + [string] $VenvName + ) + + $VenvPath = Join-Path (Get-Location) $VenvName + $ActivateScript = Join-Path $VenvPath "Scripts\Activate.ps1" + + if (Test-Path $ActivateScript) { + Write-Host "Activating virtual environment '$VenvName'..." + & $ActivateScript + } else { + Write-Warning "Virtual environment '$VenvName' not found at '$VenvPath'. Trying to use current Python environment." + } +} + +function Install-PackageInVenv { + <# + .SYNOPSIS + Install a package in the current virtual environment + .PARAMETER PackageName + The name of the package to install + .PARAMETER FromSource + Whether to install from source (editable install) + #> + param( + [Parameter(Mandatory=$true)] + [string] $PackageName, + + [Parameter(Mandatory=$false)] + [bool] $FromSource = $false + ) + + if ($FromSource) { + Write-Host "Installing '$PackageName' from source (editable install)..." + pip install -e ".$PackageName" + } else { + Write-Host "Installing '$PackageName' from PyPI..." + pip install $PackageName + } +} + +# Export functions +Export-ModuleMember -Function Enable-Venv, Get-VenvName, New-VenvForPackage, Use-Venv, Install-PackageInVenv \ No newline at end of file From a72288f70cb2c095c2674b250c0c991fa713d0d6 Mon Sep 17 00:00:00 2001 From: Xinyi Joffre Date: Fri, 3 Oct 2025 01:11:24 -0700 Subject: [PATCH 2/5] Fix install from source --- .../tests.live/Install-Artifacts.ps1 | 10 +++----- azure-quantum/tests.live/Run.ps1 | 18 ------------- build/package-utils.psm1 | 25 ++++--------------- build/venv-utils.psm1 | 20 +++------------ 4 files changed, 13 insertions(+), 60 deletions(-) diff --git a/azure-quantum/tests.live/Install-Artifacts.ps1 b/azure-quantum/tests.live/Install-Artifacts.ps1 index c22895919..911c52079 100644 --- a/azure-quantum/tests.live/Install-Artifacts.ps1 +++ b/azure-quantum/tests.live/Install-Artifacts.ps1 @@ -9,11 +9,8 @@ $PackageDir = Split-Path -parent $PSScriptRoot; $PackageName = $PackageDir | Split-Path -Leaf; $RootDir = Split-Path -parent $PackageDir; -Import-Module (Join-Path $RootDir "build" "venv-utils.psm1"); -Import-Module (Join-Path $RootDir "build" "package-utils.psm1"); - -# Enable venv support -Enable-Venv +Import-Module (Join-Path $RootDir "build" "venv-utils.psm1") -Force; +Import-Module (Join-Path $RootDir "build" "package-utils.psm1") -Force; New-VenvForPackage -PackageName $PackageName @@ -23,7 +20,8 @@ if (-not $Env:PYTHON_OUTDIR) { "== We will install $PackageName from source." | Write-Host "" | Write-Host - Install-PackageInEnv -PackageName "$PackageName[qiskit,cirq,qsharp,dev]" -FromSource $True + $PackageWithExtras = "$PackageName[qiskit,cirq,qsharp,dev]" + Install-PackageInEnv -PackageName $PackageWithExtras -FromSource $True "" | Write-Host "== $PackageName installed from source. ==" | Write-Host diff --git a/azure-quantum/tests.live/Run.ps1 b/azure-quantum/tests.live/Run.ps1 index c5ec64332..1873ee27d 100644 --- a/azure-quantum/tests.live/Run.ps1 +++ b/azure-quantum/tests.live/Run.ps1 @@ -27,24 +27,6 @@ if ($True -eq $SkipInstall) { & (Join-Path $PSScriptRoot Install-Artifacts.ps1) } -Enable-Venv - -# Try activating the virtual environment for azure-quantum -if ([string]::IsNullOrEmpty($PackageName) -or ($PackageName -eq "azure-quantum")) { - try { - $VenvPath = Join-Path (Split-Path -parent $PSScriptRoot) "venv" - if (Test-Path $VenvPath) { - Use-Venv -VenvName "venv" - } - } - catch { - Write-Host "##[warning]Failed to activate virtual environment." - } -} - -$EnvName = GetEnvName -PackageName $PackageName -Use-Venv -VenvName $EnvName - function PyTestMarkExpr() { param ( [string[]] $AzureQuantumCapabilities diff --git a/build/package-utils.psm1 b/build/package-utils.psm1 index 7195e67bb..06e0243f3 100644 --- a/build/package-utils.psm1 +++ b/build/package-utils.psm1 @@ -30,7 +30,10 @@ function Install-PackageInEnv { if ($FromSource) { Write-Host "Installing '$PackageName' from source (editable install)..." - pip install -e "[$PackageName]" + $ParentPath = Split-Path -parent $PSScriptRoot + $AbsPackageName = Join-Path $ParentPath $PackageName + Write-Host "##[info]Install package $AbsPackageName in development mode for env $EnvName" + pip install -e $AbsPackageName } elseif (-not [string]::IsNullOrEmpty($BuildArtifactPath)) { Write-Host "Installing '$PackageName' from build artifacts at '$BuildArtifactPath'..." $WheelFiles = Get-ChildItem -Path $BuildArtifactPath -Filter "*.whl" @@ -46,23 +49,5 @@ function Install-PackageInEnv { } } -function GetEnvName { - <# - .SYNOPSIS - Get the environment name for a package - .PARAMETER PackageName - The name of the package - #> - param( - [Parameter(Mandatory=$true)] - [string] $PackageName - ) - - if ([string]::IsNullOrEmpty($PackageName) -or ($PackageName -eq "azure-quantum")) { - return "venv" - } - return "venv-$PackageName" -} - # Export functions -Export-ModuleMember -Function Install-PackageInEnv, GetEnvName \ No newline at end of file +Export-ModuleMember -Function Install-PackageInEnv \ No newline at end of file diff --git a/build/venv-utils.psm1 b/build/venv-utils.psm1 index 2a4c858e8..911a5f708 100644 --- a/build/venv-utils.psm1 +++ b/build/venv-utils.psm1 @@ -6,22 +6,6 @@ PowerShell utilities for managing Python virtual environments #> -function Enable-Venv { - <# - .SYNOPSIS - Initialize Python virtual environment support in the current session - #> - # Check if Python is available - try { - $PythonVersion = python --version 2>&1 - Write-Host "Using Python: $PythonVersion" - } - catch { - Write-Error "Python is not available in PATH. Please install Python first." - throw - } -} - function Get-VenvName { <# .SYNOPSIS @@ -90,6 +74,10 @@ function Use-Venv { if (Test-Path $ActivateScript) { Write-Host "Activating virtual environment '$VenvName'..." + # Ensure prompt function exists to avoid activation errors + if (-not (Get-Command prompt -ErrorAction SilentlyContinue)) { + function prompt { "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) " } + } & $ActivateScript } else { Write-Warning "Virtual environment '$VenvName' not found at '$VenvPath'. Trying to use current Python environment." From 91af42e7e9bff92ae9e390fa891a3a678c65e499 Mon Sep 17 00:00:00 2001 From: Xinyi Joffre Date: Fri, 3 Oct 2025 15:49:43 -0700 Subject: [PATCH 3/5] Add Powershell to prerequisites in README --- azure-quantum/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-quantum/README.md b/azure-quantum/README.md index c269a424e..bcb346de4 100644 --- a/azure-quantum/README.md +++ b/azure-quantum/README.md @@ -87,6 +87,7 @@ For developers who want to contribute to this package or run tests locally, foll - Python 3.9 or later - Git +- Powershell ### Setting up the development environment From 5f14ef4d838ce3858326e4e8c63f0df4d5896e1f Mon Sep 17 00:00:00 2001 From: Xinyi Joffre Date: Fri, 3 Oct 2025 15:50:56 -0700 Subject: [PATCH 4/5] Remove pytest-regressions from requirements --- azure-quantum/requirements-dev.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure-quantum/requirements-dev.txt b/azure-quantum/requirements-dev.txt index db72c8fcc..a25f55d04 100644 --- a/azure-quantum/requirements-dev.txt +++ b/azure-quantum/requirements-dev.txt @@ -1,5 +1,4 @@ pytest>=7.1.2 -pytest-regressions vcrpy>=4.3.1 # fixes https://github.com/kevin1024/vcrpy/issues/688 azure-devtools>=1.2.0,<2.0 -graphviz>=0.20.1 \ No newline at end of file +graphviz>=0.20.1 From ca46cb7a0b3106970159a6eec19ec1f16d3a2e0f Mon Sep 17 00:00:00 2001 From: Xinyi Joffre Date: Fri, 3 Oct 2025 15:52:09 -0700 Subject: [PATCH 5/5] Change virtual environment activation command to PowerShell Updated instructions for activating the virtual environment from bash to PowerShell. --- azure-quantum/tests/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-quantum/tests/README.md b/azure-quantum/tests/README.md index 246619dc3..6e24c34fc 100644 --- a/azure-quantum/tests/README.md +++ b/azure-quantum/tests/README.md @@ -10,8 +10,8 @@ Before running the unit tests, set up your development environment using the ven ``` This will install the package with common optional dependencies (qiskit, cirq, qsharp). To install additional provider dependencies, run: -```bash -source venv/bin/activate # Activate the virtual environment first +```powershell +./venv/Scripts/activate # Activate the virtual environment first pip install -e .[pulser,quil] # for specific providers pip install -e .[all] # for all providers (requires Rust toolchain) ```