Skip to content

Consolidate duplicate Python helpers between hook executor and framework service #7570

Description

@wbreza

Summary

The multi-language hooks feature (PR #7451) introduced pkg/tools/language/python_executor.go which contains Python venv/pip orchestration logic that partially duplicates existing code in pkg/project/framework_service_python.go. Both files independently import pkg/tools/python/ for low-level operations but reimplement the orchestration layer around those calls.

This issue tracks extracting shared helpers into pkg/tools/python/ where both consumers already depend, eliminating ~80-100 lines of duplication.

Duplications Identified

Venv Naming ({baseName}_env)

  • Executor: venvNameForDir(projectDir string) string (python_executor.go:408-416)
  • Framework: getVenvName(serviceConfig *ServiceConfig) string (framework_service_python.go:185-192)
  • Action: Extract to python.VenvNameForDir(projectDir string) string
  • Character-for-character identical logic with different parameter types.

Venv Ensure (stat → create)

  • Executor: ensureVenv() — stat, is-dir check, errors.Is, create (python_executor.go:184-219)
  • Framework: Inline in Restore() — stat, os.IsNotExist, create (framework_service_python.go:62-79)
  • Action: Extract to python.Cli.EnsureVirtualEnv(ctx, workingDir, name, env) error
  • Use executor's stricter implementation (has directory type check, modern errors.Is).

Dep Install Dispatch (requirements.txt vs pyproject.toml)

  • Executor: installDeps() — switch on depFile (python_executor.go:223-251)
  • Framework: Inline in Restore() — if/else on depFile (framework_service_python.go:82-96)
  • Action: Extract to python.Cli.InstallDependencies(ctx, dir, venvName, depFile, env) error
  • Detection stays separate (framework checks one dir; executor walks up). Only dispatch is shared.

Python Command Resolution (py/python/python3)

  • Executor: resolvePythonCmd(runner) string (python_executor.go:313-332)
  • Framework: Uses python.Cli.checkPath() — private (python.go:151-173)
  • Action: Export existing checkPath() as python.Cli.ResolveCommand() (string, error)
  • Same resolution order (Windows: py→python; Unix: python3).

Venv Directory Layout (Scripts/bin)

  • Executor: resolvePythonPath() — builds venv python binary path (python_executor.go:297-307)
  • Framework: Inline in Run() — builds venv activation script path (python.go:130-136)
  • Action: Extract to python.VenvPythonPath(venvDir) string + python.VenvActivateCmd(venvDir) string

What Stays in the Executor (NOT consolidated)

These are hook-specific features the framework service doesn't need:

  • detectExistingVenv() — checks VIRTUAL_ENV env var, .venv, venv dirs
  • DiscoverProjectFile() — walk-up directory search from script location
  • hasPyvenvCfg() — venv validation heuristic
  • Direct python binary invocation (vs shell activation)

Dependency Graph

\
pkg/tools/python/ ← both already import this (leaf package)
↑ ↑
| |
language/ project/
(hook executor) (framework service)
\\

No circular dependency risk — python/ imports neither language/ nor project/.

Estimated Impact

  • ~80-100 lines removed across both consumers
  • ~60 lines added to pkg/tools/python/ (mostly moved, not new)
  • pythonTools interface simplified to 3 methods

Related

Metadata

Metadata

Assignees

Labels

enhancementNew feature or improvement

Fields

No fields configured for Feature.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions