@@ -2,31 +2,113 @@ package pythontest
22
33import (
44 "context"
5+ "errors"
6+ "fmt"
7+ "os"
8+ "os/exec"
59 "path/filepath"
10+ "runtime"
611 "strings"
12+ "testing"
713
814 "github.com/databricks/cli/internal/testutil"
915 "github.com/databricks/cli/libs/python"
1016 "github.com/stretchr/testify/require"
1117)
1218
13- func RequirePythonVENV (t testutil.TestingT , ctx context.Context , pythonVersion string , checkVersion bool ) string {
14- tmpDir := t .TempDir ()
15- testutil .Chdir (t , tmpDir )
19+ type VenvOpts struct {
20+ // input
21+ PythonVersion string
22+ skipVersionCheck bool
1623
17- venvName := testutil . RandomName ( "test-venv-" )
18- testutil . RunCommand ( t , "uv" , "venv" , venvName , "--python" , pythonVersion , "--seed" )
19- testutil . InsertVirtualenvInPath ( t , filepath . Join ( tmpDir , venvName ))
24+ // input/output
25+ Dir string
26+ Name string
2027
21- pythonExe , err := python .DetectExecutable (ctx )
22- require .NoError (t , err )
23- require .Contains (t , pythonExe , venvName )
28+ // output:
29+ // Absolute path to venv
30+ EnvPath string
31+
32+ // Absolute path to venv/bin or venv/Scripts, depending on OS
33+ BinPath string
34+
35+ // Absolute path to python binary
36+ PythonExe string
37+ }
38+
39+ func CreatePythonEnv (opts * VenvOpts ) error {
40+ if opts == nil || opts .PythonVersion == "" {
41+ return errors .New ("PythonVersion must be provided" )
42+ }
43+ if opts .Name == "" {
44+ opts .Name = testutil .RandomName ("test-venv-" )
45+ }
46+ if opts .Dir != "" {
47+ opts .Dir = "."
48+ }
49+
50+ cmd := exec .Command ("uv" , "venv" , opts .Name , "--python" , opts .PythonVersion , "--seed" , "-q" )
51+ cmd .Stdout = os .Stdout
52+ cmd .Stderr = os .Stderr
53+ cmd .Dir = opts .Dir
54+ err := cmd .Run ()
55+ if err != nil {
56+ return err
57+ }
58+
59+ opts .EnvPath , err = filepath .Abs (filepath .Join (opts .Dir , opts .Name ))
60+ if err != nil {
61+ return err
62+ }
63+
64+ _ , err = os .Stat (opts .EnvPath )
65+ if err != nil {
66+ return fmt .Errorf ("cannot stat EnvPath %s: %s" , opts .EnvPath , err )
67+ }
68+
69+ if runtime .GOOS == "windows" {
70+ // https://github.com/pypa/virtualenv/commit/993ba1316a83b760370f5a3872b3f5ef4dd904c1
71+ opts .BinPath = filepath .Join (opts .EnvPath , "Scripts" )
72+ opts .PythonExe = filepath .Join (opts .BinPath , "python.exe" )
73+ } else {
74+ opts .BinPath = filepath .Join (opts .EnvPath , "bin" )
75+ opts .PythonExe = filepath .Join (opts .BinPath , "python3" )
76+ }
77+
78+ _ , err = os .Stat (opts .BinPath )
79+ if err != nil {
80+ return fmt .Errorf ("cannot stat BinPath %s: %s" , opts .BinPath , err )
81+ }
82+
83+ _ , err = os .Stat (opts .PythonExe )
84+ if err != nil {
85+ return fmt .Errorf ("cannot stat PythonExe %s: %s" , opts .PythonExe , err )
86+ }
2487
25- if checkVersion {
26- actualVersion := testutil .CaptureCommandOutput (t , pythonExe , "--version" )
27- expectVersion := "Python " + pythonVersion
28- require .True (t , strings .HasPrefix (actualVersion , expectVersion ), "Running %s --version: Expected %v, got %v" , pythonExe , expectVersion , actualVersion )
88+ if ! opts .skipVersionCheck {
89+ cmd := exec .Command (opts .PythonExe , "--version" )
90+ out , err := cmd .CombinedOutput ()
91+ if err != nil {
92+ return fmt .Errorf ("Failed to run %s --version: %s" , opts .PythonExe , err )
93+ }
94+ outString := string (out )
95+ expectVersion := "Python " + opts .PythonVersion
96+ if ! strings .HasPrefix (outString , expectVersion ) {
97+ return fmt .Errorf ("Unexpected output from %s --version: %v (expected %v)" , opts .PythonExe , outString , expectVersion )
98+ }
2999 }
30100
31- return tmpDir
101+ return nil
102+ }
103+
104+ func RequireActivatedPythonEnv (t * testing.T , ctx context.Context , opts * VenvOpts ) {
105+ err := CreatePythonEnv (opts )
106+ require .NoError (t , err )
107+ require .DirExists (t , opts .BinPath )
108+
109+ testutil .InsertPathEntry (t , opts .BinPath )
110+
111+ pythonExe , err := python .DetectExecutable (ctx )
112+ require .NoError (t , err )
113+ require .Equal (t , filepath .Dir (pythonExe ), filepath .Dir (opts .PythonExe ))
32114}
0 commit comments