Files
pack/core/providers/python/python_test.go
T
zeekay 7844a60aff refactor(pack): modernize to github.com/hanzoai/pack and remove upstream branding
- Migrate module path to github.com/hanzoai/pack across all Go packages
- Remove legacy upstream docs and competitor brand references
- Modernize LLM.md and mise.toml for pristine Hanzo Pack builder
2026-09-04 00:40:42 -07:00

239 lines
5.6 KiB
Go

package python
import (
"testing"
"github.com/hanzoai/pack/core/generate"
"github.com/hanzoai/pack/core/plan"
"github.com/stretchr/testify/require"
testingUtils "github.com/hanzoai/pack/core/testing"
)
func TestDetect(t *testing.T) {
tests := []struct {
name string
path string
want bool
}{
{
name: "pip",
path: "../../../examples/python-pip",
want: true,
},
{
name: "poetry",
path: "../../../examples/python-poetry",
want: true,
},
{
name: "pdm",
path: "../../../examples/python-pdm",
want: true,
},
{
name: "uv",
path: "../../../examples/python-uv",
want: true,
},
{
name: "bot.py only",
path: "../../../examples/python-bot-only",
want: true,
},
{
name: "no python",
path: "../../../examples/go-mod",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := testingUtils.CreateGenerateContext(t, tt.path)
provider := PythonProvider{}
got, err := provider.Detect(ctx)
require.NoError(t, err)
require.Equal(t, tt.want, got)
})
}
}
func TestUsesBinaryPsycopg(t *testing.T) {
tests := []struct {
name string
path string
want bool
}{
{
name: "psycopg2-binary",
path: "../../../examples/python-system-deps",
want: true,
},
{
name: "psycopg[binary]",
path: "../../../examples/python-psycopg-binary",
want: true,
},
{
name: "psycopg (non-binary)",
path: "../../../examples/python-latest-psycopg",
want: false,
},
{
name: "psycopg2 (django)",
path: "../../../examples/python-django",
want: false,
},
{
name: "psycopg2 in workspace sub-package (non-binary)",
path: "../../../examples/python-uv-workspace-postgres",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := testingUtils.CreateGenerateContext(t, tt.path)
provider := PythonProvider{}
got := provider.usesBinaryPsycopg(ctx)
require.Equal(t, tt.want, got)
})
}
}
func TestUsesPostgres(t *testing.T) {
tests := []struct {
name string
path string
want bool
}{
{
name: "psycopg2-binary should not need apt packages",
path: "../../../examples/python-system-deps",
want: false,
},
{
name: "psycopg[binary] should not need apt packages",
path: "../../../examples/python-psycopg-binary",
want: false,
},
{
name: "psycopg (non-binary) needs apt packages",
path: "../../../examples/python-latest-psycopg",
want: true,
},
{
name: "psycopg2 (django) needs apt packages",
path: "../../../examples/python-django",
want: true,
},
{
name: "psycopg2 in workspace sub-package needs apt packages",
path: "../../../examples/python-uv-workspace-postgres",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := testingUtils.CreateGenerateContext(t, tt.path)
provider := PythonProvider{}
got := provider.usesPostgres(ctx)
require.Equal(t, tt.want, got)
})
}
}
func TestUsesProductionPlaywrightDependency(t *testing.T) {
tests := []struct {
name string
path string
dependency string
want bool
}{
{
name: "PEP 621 production dependency",
path: "../../../examples/python-playwright",
dependency: "playwright",
want: true,
},
{
// python-playwright declares pytest in dependency-groups.dev.
name: "PEP 735 development dependency",
path: "../../../examples/python-playwright",
dependency: "pytest",
want: false,
},
{
name: "Poetry production dependency",
path: "../../../examples/python-poetry",
dependency: "flask",
want: true,
},
{
name: "Pipenv production dependency",
path: "../../../examples/python-pipfile",
dependency: "cowsay",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := testingUtils.CreateGenerateContext(t, tt.path)
provider := PythonProvider{}
require.Equal(t, tt.want, provider.usesProductionDep(ctx, tt.dependency))
})
}
}
func TestPlaywrightInstallationIsOptIn(t *testing.T) {
t.Run("does not install by default", func(t *testing.T) {
ctx := testingUtils.CreateGenerateContext(t, "../../../examples/python-playwright")
provider := PythonProvider{}
require.NoError(t, provider.Plan(ctx))
require.False(t, stepHasExecCommand(ctx, "install", "playwright install --only-shell"))
require.NotContains(t, ctx.Deploy.AptPackages, "libnss3")
})
t.Run("install when enabled", func(t *testing.T) {
ctx := testingUtils.CreateGenerateContext(t, "../../../examples/python-playwright")
ctx.Env.Variables["RAILPACK_PYTHON_PLAYWRIGHT_INSTALL"] = "1"
provider := PythonProvider{}
require.NoError(t, provider.Plan(ctx))
require.True(t, stepHasExecCommand(ctx, "install", "playwright install --only-shell"))
require.Contains(t, ctx.Deploy.AptPackages, "libnss3")
})
}
func TestDependencySpecMatches(t *testing.T) {
require.True(t, dependencySpecMatches("Playwright[chromium]>=1.49", "playwright"))
require.True(t, dependencySpecMatches("playwright @ https://example.com/playwright.whl", "playwright"))
require.False(t, dependencySpecMatches("pytest-playwright>=0.7", "playwright"))
}
func stepHasExecCommand(ctx *generate.GenerateContext, stepName string, command string) bool {
step := ctx.GetStepByName(stepName)
if step == nil {
return false
}
commandStep, ok := (*step).(*generate.CommandStepBuilder)
if !ok {
return false
}
for _, candidate := range commandStep.Commands {
execCommand, ok := candidate.(plan.ExecCommand)
if ok && execCommand.Cmd == command {
return true
}
}
return false
}