Skip to content

lang.python #

Python Environment Management with UV

This module provides modern Python environment management using uv - a fast Python package installer and resolver written in Rust.

Features

  • Modern Tooling: Uses uv instead of legacy pip for fast package management
  • Template-Based: Generates pyproject.toml, env.sh, and install.sh from templates
  • No Database Dependencies: Relies on Python's native package management instead of manual state tracking
  • Backward Compatible: Legacy pip() methods still work but use uv under the hood
  • Project-Based: Each environment is a proper Python project with pyproject.toml

Quick Start

import incubaid.herolib.lang.python

// Create a new Python environment
py := python.new(
    name: 'my_project'
    dependencies: ['requests', 'click', 'pydantic']
    dev_dependencies: ['pytest', 'black', 'mypy']
    python_version: '3.11'
)!

// Add more dependencies
py.add_dependencies(['fastapi'], false)! // production dependency
py.add_dependencies(['pytest-asyncio'], true)! // dev dependency

// Execute Python code
result := py.exec(cmd: '''
import requests
response = requests.get("https://api.github.com")
print("==RESULT==")
print(response.status_code)
''')!

println('Status code: ${result}')

Environment Structure

Each Python environment creates:

~/hero/python/{name}/
├── .venv/              # Virtual environment (created by uv)
├── pyproject.toml      # Project configuration
├── uv.lock            # Dependency lock file
├── env.sh             # Environment activation script
├── install.sh         # Installation script
└── README.md          # Project documentation

API Reference

Creating Environments

// Basic environment
py := python.new()! // Creates 'default' environment

// Custom environment with dependencies
py := python.new(
    name: 'web_scraper'
    dependencies: ['requests', 'beautifulsoup4', 'lxml']
    dev_dependencies: ['pytest', 'black']
    python_version: '3.11'
    description: 'Web scraping project'
    reset: true // Force recreation
)!

Package Management

// Add production dependencies
py.add_dependencies(['numpy', 'pandas'], false)!

// Add development dependencies  
py.add_dependencies(['jupyter', 'matplotlib'], true)!

// Remove dependencies
py.remove_dependencies(['old_package'], false)!

// Legacy methods (still work)
py.pip('requests,click')! // Comma-separated
py.pip_uninstall('old_package')!

// Update all dependencies
py.update()!

// Sync dependencies (install from pyproject.toml)
py.sync()!

Environment Information

// Check if environment exists
if py.exists() {
    println('Environment is ready')
}

// List installed packages
packages := py.list_packages()!
for package in packages {
    println(package)
}

Freeze/Export Functionality

// Export current environment
requirements := py.freeze()!
py.freeze_to_file('requirements.txt')!

// Export with exact versions (from uv.lock)
lock_content := py.export_lock()!
py.export_lock_to_file('requirements-lock.txt')!

// Install from requirements
py.install_from_requirements('requirements.txt')!

// Restore exact environment from lock
py.restore_from_lock()!

Shell Access

// Open interactive shell in environment
py.shell()!

// Open Python REPL
py.python_shell()!

// Open IPython (if available)
py.ipython_shell()!

// Run Python script
result := py.run_script('my_script.py')!

// Run any command in environment
result := py.run('python -m pytest')!

// Run uv commands
result := py.uv_run('add --dev mypy')!

Python Code Execution

// Execute Python code with result capture
result := py.exec(
    cmd: '''
import json
data = {"hello": "world"}
print("==RESULT==")
print(json.dumps(data))
'''
)!

// Execute with custom delimiters
result := py.exec(
    cmd: 'print("Hello World")'
    result_delimiter: '==OUTPUT=='
    ok_delimiter: '==DONE=='
)!

// Save script to file in environment
py.exec(
    cmd: 'print("Hello World")'
    python_script_name: 'hello'  // Saves as hello.py
)!

Migration from Old Implementation

Before (Database-based)

py := python.new(name: 'test')!
py.update()! // Manual pip upgrade
py.pip('requests')! // Manual package tracking

After (UV-based)

py := python.new(
    name: 'test'
    dependencies: ['requests']
)! // Automatic setup with uv

Key Changes

  1. No Database: Removed all dbfs.DB usage
  2. Automatic Setup: Environment initialization is automatic
  3. Modern Tools: Uses uv instead of pip
  4. Project Files: Generates proper Python project structure
  5. Faster: uv is significantly faster than pip
  6. Better Dependency Resolution: uv has superior dependency resolution

Shell Script Usage

Each environment generates shell scripts for manual use:

##cd ~/hero/python/my_project
source env.sh

##./install.sh

Requirements

  • uv: Install with curl -LsSf https://astral.sh/uv/install.sh | sh
  • Python 3.11+: Recommended Python version

Examples

See examples/lang/python/ for complete working examples.

Performance Notes

  • uv is 10-100x faster than pip for most operations
  • Dependency resolution is significantly improved
  • Lock files ensure reproducible environments
  • No manual state tracking reduces complexity and errors

fn new #

fn new(args_ PythonEnvArgs) !PythonEnv

struct PythonEnv #

struct PythonEnv {
pub mut:
	name string
	path pathlib.Path
}

fn (PythonEnv) add_dependencies #

fn (py PythonEnv) add_dependencies(packages []string, dev bool) !

Add dependencies to the project

fn (PythonEnv) exec #

fn (py PythonEnv) exec(args PythonExecArgs) !string

fn (PythonEnv) exists #

fn (py PythonEnv) exists() bool

Check if the Python environment exists and is properly configured

fn (PythonEnv) export_lock #

fn (py PythonEnv) export_lock() !string

Export current lock state (equivalent to uv.lock)

fn (PythonEnv) export_lock_to_file #

fn (mut py PythonEnv) export_lock_to_file(filename string) !

Export lock state to file

fn (PythonEnv) freeze #

fn (py PythonEnv) freeze() !string

Export current environment dependencies to requirements.txt

fn (PythonEnv) freeze_to_file #

fn (mut py PythonEnv) freeze_to_file(filename string) !

Export dependencies to a requirements.txt file

fn (PythonEnv) generate_all_templates #

fn (mut py PythonEnv) generate_all_templates(args TemplateArgs) !

generate_all_templates creates all template files for the Python environment

fn (PythonEnv) generate_env_script #

fn (mut py PythonEnv) generate_env_script(args TemplateArgs) !

generate_env_script creates an env.sh script from template

fn (PythonEnv) generate_install_script #

fn (mut py PythonEnv) generate_install_script(args TemplateArgs) !

generate_install_script creates an install.sh script from template

fn (PythonEnv) generate_pyproject_toml #

fn (mut py PythonEnv) generate_pyproject_toml(args TemplateArgs) !

generate_pyproject_toml creates a pyproject.toml file from template

fn (PythonEnv) generate_readme #

fn (mut py PythonEnv) generate_readme(args TemplateArgs) !

generate_readme creates a basic README.md file

fn (PythonEnv) init_env #

fn (mut py PythonEnv) init_env(args PythonEnvArgs) !

Initialize the Python environment using uv

fn (PythonEnv) install_from_requirements #

fn (py PythonEnv) install_from_requirements(filename string) !

Install dependencies from requirements.txt file

fn (PythonEnv) ipython_shell #

fn (py PythonEnv) ipython_shell() !

Open IPython if available, fallback to regular Python

fn (PythonEnv) list_packages #

fn (py PythonEnv) list_packages() ![]string

Get list of installed packages

fn (PythonEnv) pip #

fn (py PythonEnv) pip(packages string) !

Legacy pip method for backward compatibility - now uses uv add

fn (PythonEnv) pip_uninstall #

fn (py PythonEnv) pip_uninstall(packages string) !

Legacy pip_uninstall method for backward compatibility - now uses uv remove

fn (PythonEnv) python_shell #

fn (py PythonEnv) python_shell() !

Open a Python REPL in the environment

fn (PythonEnv) remove_dependencies #

fn (py PythonEnv) remove_dependencies(packages []string, dev bool) !

Remove dependencies from the project

fn (PythonEnv) restore_from_lock #

fn (py PythonEnv) restore_from_lock() !

Restore environment from lock file

fn (PythonEnv) run #

fn (py PythonEnv) run(command string) !osal.Job

Run a command in the Python environment

fn (PythonEnv) run_script #

fn (py PythonEnv) run_script(script_path string) !osal.Job

Run a specific Python script in the environment

fn (PythonEnv) shell #

fn (py PythonEnv) shell() !

Open an interactive shell in the Python environment

fn (PythonEnv) sync #

fn (py PythonEnv) sync() !

Sync dependencies using uv

fn (PythonEnv) update #

fn (py PythonEnv) update() !

Update all dependencies

fn (PythonEnv) uv_run #

fn (py PythonEnv) uv_run(command string) !osal.Job

Run a uv command in the environment context

struct PythonEnvArgs #

@[params]
struct PythonEnvArgs {
pub mut:
	name             string = 'default'
	reset            bool
	python_version   string = '3.11'
	dependencies     []string
	dev_dependencies []string
	description      string = 'A Python project managed by Herolib'
}

struct PythonExecArgs #

@[params]
struct PythonExecArgs {
pub mut:
	cmd                string @[required]
	result_delimiter   string = '==RESULT=='
	ok_delimiter       string = '==OK=='
	python_script_name string // if used will put it in root of the sandbox under that name
	stdout             bool = true
}

struct TemplateArgs #

@[params]
struct TemplateArgs {
pub mut:
	name             string = 'herolib-python-project'
	version          string = '0.1.0'
	description      string = 'A Python project managed by Herolib'
	python_version   string = '3.11'
	dependencies     []string
	dev_dependencies []string
	scripts          map[string]string
}