#Requires -Version 5.1 <# .SYNOPSIS Create the conda environment "mcm-toolkit". .DESCRIPTION Three ways to build the environment, in order of preference: (default) explicit package list, installed from the "defaults" channel. Needs internet. Measured on this machine: ~14.5 min, ~3 GB download. -FromYml same, but driven by environment.yml (better for reproducing later). -CloneBase mirrors the whole base environment. NOTE: on conda 25.11 this is NOT a fast local copy -- conda replays base's full package list and downloads/installs it. Use it only when you want an exact copy of base. To work offline later, build the environment BEFORE the contest and keep the conda package cache (D:\anaconda\pkgs) intact. NOTE: this file is intentionally pure ASCII, UTF-8 without BOM, LF endings. Windows PowerShell 5.1 parses .ps1 as ANSI when there is no BOM, so non-ASCII characters (e.g. Chinese) turn into illegal bytes and cause syntax errors. .PARAMETER Name conda environment name. Default: mcm-toolkit. .PARAMETER FromYml Build from environment.yml instead of the inline package list. .PARAMETER CloneBase Clone the base environment instead of installing a explicit package list. .PARAMETER Force Remove and recreate the environment if it already exists. .EXAMPLE .\scripts\setup-conda.ps1 Create "mcm-toolkit" with the science stack (needs internet). .EXAMPLE .\scripts\setup-conda.ps1 -FromYml -Force Rebuild from environment.yml. #> [CmdletBinding()] param( [string]$Name = 'mcm-toolkit', [switch]$FromYml, [switch]$CloneBase, [switch]$Force ) $ErrorActionPreference = 'Stop' $repoRoot = Split-Path -Parent $PSScriptRoot # Packages required by pyproject.toml's core deps plus the [ml] / [graph] / # [symbolic] / [excel] / [dev] extras. SALib, pymoo and pyright are pip-only # (see install after the conda step). $packages = @( 'python=3.13', 'numpy', 'scipy', 'pandas', 'matplotlib', 'scikit-learn', 'statsmodels', 'networkx', 'sympy', 'openpyxl', 'pytest', 'ruff', 'pip' ) $pipOnly = @('SALib', 'pymoo', 'pyright') function Find-Conda { $candidates = @( "$env:USERPROFILE\anaconda3\Scripts\conda.exe", "$env:USERPROFILE\miniconda3\Scripts\conda.exe", 'D:\anaconda\Scripts\conda.exe', 'C:\ProgramData\Anaconda3\Scripts\conda.exe', 'C:\ProgramData\miniconda3\Scripts\conda.exe' ) foreach ($c in $candidates) { if (Test-Path -LiteralPath $c) { return $c } } $onPath = Get-Command conda -ErrorAction SilentlyContinue if ($onPath) { return $onPath.Source } throw 'conda not found. Install Anaconda/Miniconda first.' } $conda = Find-Conda Write-Host "[1/5] conda = $conda" # PITFALL: the Anaconda 25.x ToS plugin fetches channel metadata from # repo.anaconda.com before every create/install and crashes when offline. # This env var auto-accepts the ToS: it skips the network call while keeping # the libmamba solver (unlike --no-plugins, which disables all plugins). $env:CONDA_PLUGINS_AUTO_ACCEPT_TOS = 'yes' $env:CONDA_AUTO_UPDATE_CONDA = 'false' # PITFALL: envs_dirs and pkgs_dirs must be writable, otherwise conda fails with # NotWritableError or "Error encountered while attempting to create cache directory". Write-Host '[2/5] current envs_dirs / pkgs_dirs:' & $conda config --show envs_dirs pkgs_dirs 2>$null | ForEach-Object { Write-Host " $_" } $existing = (& $conda env list --json | ConvertFrom-Json).envs | Where-Object { (Split-Path -Leaf $_) -eq $Name } if ($existing) { if (-not $Force) { Write-Host "Environment '$Name' already exists ($existing). Use -Force to rebuild." -ForegroundColor Yellow exit 0 } Write-Host "Environment '$Name' exists, -Force given, removing first ..." & $conda env remove -n $Name -y } Write-Host '[3/5] creating the environment (this can take 10-20 minutes) ...' $sw = [Diagnostics.Stopwatch]::StartNew() if ($FromYml) { $yml = Join-Path $repoRoot 'environment.yml' if (-not (Test-Path -LiteralPath $yml)) { throw "Not found: $yml" } & $conda env create -n $Name -f $yml } elseif ($CloneBase) { & $conda create -n $Name --clone base -y } else { & $conda create -n $Name -y @packages } if ($LASTEXITCODE -ne 0) { throw "conda create failed (exit code $LASTEXITCODE)" } Write-Host (" done in {0:N0}s" -f $sw.Elapsed.TotalSeconds) $envPy = Join-Path (Split-Path -Parent (Split-Path -Parent $conda)) "envs\$Name\python.exe" if (-not (Test-Path -LiteralPath $envPy)) { $envsRoot = (& $conda config --show envs_dirs | Select-String -Pattern '\S' | Select-Object -First 1).ToString().Trim() $envPy = Join-Path $envsRoot "$Name\python.exe" } Write-Host '[4/5] installing pip-only extras (SALib, pymoo, pyright) + this project ...' & $envPy -m pip install --disable-pip-version-check --no-warn-script-location -q @pipOnly & $envPy -m pip install -e $repoRoot --no-deps --no-build-isolation --disable-pip-version-check -q Write-Host '[5/5] verifying ...' & $envPy -c "import numpy, scipy, pandas, matplotlib, sklearn, statsmodels, networkx, sympy, SALib, pymoo, mcm_toolkit; print(' numpy', numpy.__version__, '| pandas', pandas.__version__, '| sklearn', sklearn.__version__); print(' mcm_toolkit', mcm_toolkit.__version__)" Write-Host '' Write-Host 'Done. Activate with:' -ForegroundColor Green Write-Host " conda activate $Name"