Advertisement
alaestor

[ps] script to run python in venv

Mar 2nd, 2024 (edited)
1,700
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PowerShell 5.83 KB | Source Code | 0 0
  1. <#
  2. .SYNOPSIS
  3.     Creates and activates virtual environment, installs requirements, and
  4.     runs a python script. See "Get-Help path-to-script.ps1 -detailed".
  5. .DESCRIPTION
  6.     This script will perform the following actions:
  7.  
  8.     1. changes the current working directory.
  9.     2. creates and activates a python virtual environment.
  10.     3. pip installs requirements file if it exist.
  11.     4. runs the entrypoint python script with optional arguments.
  12.     5. reverts to the original working directory when finished.
  13.  
  14.     The default arguments were set up for a particular use-case: they can be
  15.     easily changed by editing the "[CmdletBinding()]" portion of this script.
  16.  
  17.     Note: If you're using pyenv make sure a global python is configured, or
  18.     that a valid ".python-version" file is present in the working_directory.
  19. .PARAMETER working_directory
  20.     -wd <String> (default: "./src/")
  21.     The working directory for the script.
  22. .PARAMETER virtual_environment
  23.     -venv <String> (default: "../.venv/")
  24.     The path to a virtual environment folder.
  25.     May be absolute or relative to the working_directory argument.
  26.     If the folder or its activate script doesn't exist, it will be created.
  27. .PARAMETER requirements
  28.     -r <String> (default: "requirements.txt")
  29.     The path to a pip-compatible requirements file.
  30.     May be absolute or relative to the working_directory argument.
  31.     For ease of use, it's not an error if the file doesn't exist.
  32. .PARAMETER entrypoint
  33.     -py <String>
  34.     Filepath to the python script to be executed.
  35.     May be absolute or relative to the working_directory argument.
  36. .PARAMETER launch_args
  37.     -args <String[]>
  38.     Arguments that will be forwarded to the executable. (None if empty)
  39. .PARAMETER dry_run
  40.     -dry
  41.     When this argument is present, the entrypoint will not be launched.
  42.     Instead, only a message will be printed.
  43. .PARAMETER verbose
  44.     Print verbose logging and debug details (Powershell feature)
  45. .NOTES
  46.     Author: Alaestor Weissman
  47.     Discord: honshitsu
  48.     Date: 2024-03
  49.     SemVer: 0.1.0
  50. #>
  51.  
  52. [CmdletBinding()]
  53. Param(
  54.     [ValidateScript({
  55.         if (-Not (Test-Path -LiteralPath $_ ) )
  56.             { throw "Working Directory folder doesn't exist." }
  57.         return $true
  58.     })]
  59.     [String] [Alias("wd")] $working_directory = "./src/",
  60.  
  61.     [ValidateNotNullorEmpty ()]
  62.     [String] [Alias("venv")] $virtual_environment = "../.venv/",
  63.  
  64.     [ValidateScript({
  65.         if ([System.IO.Path]::IsPathRooted($_)) {
  66.             $t = $_
  67.         }
  68.         else {
  69.             $t = Join-Path -Path $working_directory -ChildPath $_
  70.         }
  71.         if (-Not (Test-Path -LiteralPath $t ) )
  72.             { throw "Entrypoint doesn't exist." }
  73.         elseif (-Not (Test-Path -LiteralPath $t -PathType Leaf) )
  74.             { throw "Entrypoint is not a file." }
  75.         return $true
  76.     })]
  77.  
  78.     [ValidateNotNullorEmpty ()]
  79.     [String] [Alias("py")] $entrypoint = "main.py",
  80.  
  81.     [ValidateNotNullorEmpty ()]
  82.     [String] [Alias("r")] $requirements = "requirements.txt",
  83.  
  84.     [String[]] [Alias("args")] $launch_args=@(""),
  85.  
  86.     [Switch] [Alias("dry")] $dry_run
  87. )
  88.  
  89. $original_cwd = (Get-Item .).FullName
  90. $debug = $DebugPreference -ne "SilentlyContinue"
  91.  
  92. function main {
  93.     try
  94.     {
  95.         Write-Verbose ((
  96.             "State",
  97.             "---",
  98.             "OWD: $original_cwd",
  99.             "CWD: $working_directory",
  100.             "DRY: $($dry_run.IsPresent)",
  101.             "ENT: $entrypoint",
  102.             "ARG: $launch_args",
  103.             "REQ: $requirements",
  104.             "DBP: $DebugPreference",
  105.             "---"
  106.         )-join("`n"))
  107.  
  108.         # Enter the working directory
  109.         Set-Location -LiteralPath $working_directory
  110.  
  111.         # Create and Activate the virtual environment
  112.         InitializeVirtualEnvironment($virtual_environment)
  113.  
  114.         # Install requirements if they exist (suppressing boolean output)
  115.         [Void]$(InstallRequirements($requirements))
  116.  
  117.         # Execute the target python script
  118.         if ($dry_run.IsPresent){
  119.             Write-Host "Execution was prevented (dry_run). Would have run:"
  120.             Write-Host $entrypoint @launch_args
  121.         }
  122.         else {
  123.             python $entrypoint @launch_args
  124.         }
  125.     }
  126.     catch
  127.     {
  128.         $Host.UI.WriteErrorLine((
  129.             "---------------",
  130.             "---  ERROR  ---",
  131.             "---------------"
  132.             ) -join "`n"
  133.         )
  134.         if ($debug) {
  135.             $_ | Format-List * -Force
  136.             $_.InvocationInfo | Format-List *
  137.         }
  138.         else {
  139.             $Host.UI.WriteErrorLine(((
  140.                     [String]$_.CategoryInfo,
  141.                     [String]$_.Exception.ErrorRecord,
  142.                     [String]$_.InvocationInfo.PositionMessage
  143.                 ) -join "`n"
  144.             ))
  145.         }
  146.         $Host.UI.WriteErrorLine("---------------")
  147.     }
  148.     finally
  149.     {
  150.         # Return to the original working directory
  151.         Set-Location -LiteralPath $original_cwd
  152.  
  153.         # Exit virtual environment if the command to do so is available
  154.         if ((Get-Command "deactivate" -ErrorAction SilentlyContinue) -ne $null) {
  155.             deactivate
  156.         }
  157.     }
  158.  
  159.     Exit
  160. }
  161.  
  162. # Creates and activates the virtual environment folder. Throws on error
  163. function InitializeVirtualEnvironment($folderpath) {
  164.     # Ensure we have python
  165.     if ((Get-Command "python" -ErrorAction SilentlyContinue) -eq $null) {
  166.         throw "Python was not found"
  167.     }
  168.  
  169.     $activate = Join-Path -Path $folderpath -ChildPath "Scripts\Activate.ps1"
  170.  
  171.     # Create virtual environment if it doesn't already exist
  172.     if (-not (Test-Path $activate)) {
  173.         python -m venv $folderpath
  174.         if ($LastExitCode -ne 0) {
  175.             throw "Failed to create virtual environment"
  176.         }
  177.     }
  178.  
  179.     # Ensure virtual environment's activate script exist
  180.     if (-not (Test-Path $activate)) {
  181.         throw "Virtual environment or activate script not found"
  182.     }
  183.  
  184.     # Activate virtual environment
  185.     & $activate
  186.  
  187.     # Ensure Python is running in a virtual environment
  188.     python -c 'import sys;sys.exit(0 if sys.prefix != sys.base_prefix else -1)'
  189.     if ($LastExitCode -ne 0) {
  190.         throw "Python appears to not be running in a virtual environment"
  191.     }
  192. }
  193.  
  194. # Returns true if successful, false if file not found. Throws on error
  195. function InstallRequirements($filepath) {
  196.     if (Test-Path $filepath) {
  197.         pip install -r $filepath --quiet --disable-pip-version-check
  198.         if ($LastExitCode -ne 0) {
  199.             throw "Failed to install the requirements from $filepath"
  200.         }
  201.         return $true
  202.     }
  203.     return $false
  204. }
  205.  
  206. main
  207.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement