rage

module
v0.0.0-...-d353cf6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 10, 2026 License: MIT

README

RAGE

Really Adequate Go-python Engine

RAGE is an embeddable Python 3.14 runtime written in Go. It allows you to run Python code directly from your Go applications without any external dependencies or CGO.

Features

  • Pure Go implementation - no CGO, no external Python installation required
  • Embeddable - designed to be used as a library in Go applications
  • Timeout support - prevent infinite loops with execution timeouts
  • Context cancellation - integrate with Go's context for graceful shutdown
  • Standard library modules - math, random, string, sys, time, re, collections, json, os, datetime, typing, asyncio, csv, itertools, functools
  • Go interoperability - call Go functions from Python and vice versa

Installation

go get github.com/ATSOTECK/rage

Quick Start

Run Python Code
package main

import (
    "fmt"
    "log"

    "github.com/ATSOTECK/rage/pkg/rage"
)

func main() {
    // Simple one-liner
    result, err := rage.Run(`print("Hello from Python!")`)
    if err != nil {
        log.Fatal(err)
    }

    // Evaluate an expression
    result, err = rage.Eval(`2 ** 10`)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(result) // 1024
}
Using State for More Control
package main

import (
    "fmt"
    "log"

    "github.com/ATSOTECK/rage/pkg/rage"
)

func main() {
    // Create a new execution state
    state := rage.NewState()
    defer state.Close()

    // Set variables accessible from Python
    state.SetGlobal("name", rage.String("World"))
    state.SetGlobal("count", rage.Int(42))

    // Run Python code
    _, err := state.Run(`
greeting = "Hello, " + name + "!"
doubled = count * 2
numbers = [1, 2, 3, 4, 5]
total = sum(numbers)
    `)
    if err != nil {
        log.Fatal(err)
    }

    // Get variables set by Python
    fmt.Println(state.GetGlobal("greeting")) // Hello, World!
    fmt.Println(state.GetGlobal("doubled"))  // 84
    fmt.Println(state.GetGlobal("total"))    // 15
}
Registering Go Functions
package main

import (
    "fmt"
    "strings"

    "github.com/ATSOTECK/rage/pkg/rage"
)

func main() {
    state := rage.NewState()
    defer state.Close()

    // Register a Go function callable from Python
    state.Register("shout", func(s *rage.State, args ...rage.Value) rage.Value {
        if len(args) == 0 {
            return rage.None
        }
        text, _ := rage.AsString(args[0])
        return rage.String(strings.ToUpper(text) + "!")
    })

    // Call it from Python
    state.Run(`message = shout("hello world")`)
    fmt.Println(state.GetGlobal("message")) // HELLO WORLD!
}
Timeouts and Context
package main

import (
    "context"
    "fmt"
    "time"

    "github.com/ATSOTECK/rage/pkg/rage"
)

func main() {
    // Using timeout
    _, err := rage.RunWithTimeout(`
while True:
    pass  # infinite loop
    `, 2*time.Second)
    fmt.Println(err) // execution timeout

    // Using context
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()

    state := rage.NewState()
    defer state.Close()

    _, err = state.RunWithContext(ctx, `
x = 0
while True:
    x += 1
    `)
    fmt.Println(err) // context deadline exceeded
}

Controlling Standard Library Modules

By default, NewState() enables all available stdlib modules. For more control:

// Create state with only specific modules
state := rage.NewStateWithModules(
    rage.WithModule(rage.ModuleMath),
    rage.WithModule(rage.ModuleString),
)
defer state.Close()

// Or enable multiple at once
state := rage.NewStateWithModules(
    rage.WithModules(rage.ModuleMath, rage.ModuleString, rage.ModuleTime),
)

// Create a bare state with no modules
state := rage.NewBareState()
state.EnableModule(rage.ModuleMath)    // Enable one
state.EnableAllModules()                // Or enable all later

// Check what's enabled
if state.IsModuleEnabled(rage.ModuleMath) {
    fmt.Println("Math module is available")
}
Available Modules
Module Constant Description
math rage.ModuleMath Mathematical functions (sin, cos, sqrt, etc.)
random rage.ModuleRandom Random number generation
string rage.ModuleString String constants (ascii_letters, digits, etc.)
sys rage.ModuleSys System information (version, platform)
time rage.ModuleTime Time functions (time, sleep)
re rage.ModuleRe Regular expressions
collections rage.ModuleCollections Container datatypes (Counter, defaultdict)
json rage.ModuleJSON JSON encoding and decoding
os rage.ModuleOS OS interface (environ, path manipulation)
datetime rage.ModuleDatetime Date and time types
typing rage.ModuleTyping Type hint support
asyncio rage.ModuleAsyncio Basic async/await support
csv rage.ModuleCSV CSV file reading and writing
itertools rage.ModuleItertools Iterator building blocks (chain, combinations, permutations, etc.)
functools rage.ModuleFunctools Higher-order functions (partial, reduce, lru_cache, wraps)
io rage.ModuleIO File I/O operations

Working with Values

RAGE uses the rage.Value interface to represent Python values.

Creating Values
// Primitives
none := rage.None
b := rage.Bool(true)
i := rage.Int(42)
f := rage.Float(3.14)
s := rage.String("hello")

// Collections
list := rage.List(rage.Int(1), rage.Int(2), rage.Int(3))
tuple := rage.Tuple(rage.String("a"), rage.String("b"))
dict := rage.Dict("name", rage.String("Alice"), "age", rage.Int(30))

// From Go values (automatic conversion)
val := rage.FromGo(map[string]any{
    "numbers": []any{1, 2, 3},
    "active":  true,
})
Type Checking
if rage.IsInt(val) {
    n, _ := rage.AsInt(val)
    fmt.Println("Integer:", n)
}

if rage.IsList(val) {
    items, _ := rage.AsList(val)
    for _, item := range items {
        fmt.Println(item)
    }
}

if rage.IsDict(val) {
    dict, _ := rage.AsDict(val)
    for k, v := range dict {
        fmt.Printf("%s: %v\n", k, v)
    }
}
Converting to Go Values
val := state.GetGlobal("result")

// Get the underlying Go value
goVal := val.GoValue()

// Or use type-specific helpers
if n, ok := rage.AsInt(val); ok {
    fmt.Println("Got integer:", n)
}

Compile Once, Run Many

For repeated execution, compile once and run multiple times:

state := rage.NewState()
defer state.Close()

// Compile once
code, err := state.Compile(`result = x * 2`, "multiply.py")
if err != nil {
    log.Fatal(err)
}

// Execute multiple times with different inputs
for i := 0; i < 5; i++ {
    state.SetGlobal("x", rage.Int(int64(i)))
    state.Execute(code)
    fmt.Println(state.GetGlobal("result"))
}
// Output: 0, 2, 4, 6, 8

Error Handling

// Compilation errors
_, err := rage.Run(`def broken syntax`)
if compErr, ok := err.(*rage.CompileErrors); ok {
    for _, e := range compErr.Errors {
        fmt.Println("Compile error:", e)
    }
}

// Runtime errors
_, err = rage.Run(`x = 1 / 0`)
if err != nil {
    fmt.Println("Runtime error:", err)
}

Current Status

RAGE is under active development. Currently supported:

Implemented
  • Data types: None, bool, int, float, str, bytes, bytearray, list, tuple, dict, set, range, slice
  • Operators: arithmetic, comparison, logical, bitwise, in-place operations
  • Control flow: if/elif/else, for, while, break, continue, pass, match/case
  • Functions: def, lambda, recursion, closures, *args, **kwargs, default arguments
  • Classes: class definitions, __init__, instance attributes, methods, inheritance, properties, classmethods, staticmethods
  • Exception handling: try/except/else/finally, raise, custom exception types
  • Generators: yield, yield from, generator expressions
  • Decorators: function and class decorators
  • Comprehensions: list [x for x in items], dict {k: v for k, v in items}, set {x for x in items}
  • Imports: import, from...import, relative imports
  • Context managers: with statement support
  • F-strings: formatted string literals with format specs
  • Walrus operator: assignment expressions (:=)
  • Built-in functions: print, len, range, str, int, float, bool, list, dict, tuple, set, bytes, bytearray, type, isinstance, issubclass, abs, min, max, sum, enumerate, zip, map, filter, any, all, reversed, sorted, repr, input, ord, chr, hasattr, getattr, setattr, delattr, dir, vars, id, pow, divmod, hex, oct, bin, round, callable, property, classmethod, staticmethod, super, iter, next
Not Yet Implemented
  • Full multiple inheritance (MRO is simplified)
  • Full async/await (basic support via asyncio module)
Security Notes

Reflection builtins (globals, locals, compile, exec, eval) are opt-in and disabled by default. Enable them explicitly if needed:

state := rage.NewStateWithModules(
    rage.WithAllModules(),
    rage.WithBuiltin(rage.BuiltinGlobals),
    rage.WithBuiltin(rage.BuiltinExec),
)

Thread Safety

Each State is NOT safe for concurrent use. Create separate States for concurrent execution, or use appropriate synchronization.

// Safe: separate states per goroutine
for i := 0; i < 10; i++ {
    go func(n int) {
        state := rage.NewState()
        defer state.Close()
        state.SetGlobal("n", rage.Int(int64(n)))
        state.Run(`result = n * n`)
    }(i)
}

License

MIT

Contributing

pls

Directories

Path Synopsis
cmd
rage command
internal
stdlib
Package stdlib provides standard library modules for the RAGE Python runtime.
Package stdlib provides standard library modules for the RAGE Python runtime.
pkg
rage
Package rage provides a public API for embedding the RAGE Python runtime in Go applications.
Package rage provides a public API for embedding the RAGE Python runtime in Go applications.
test
integration command
Package main runs all Python test scripts and validates their output.
Package main runs all Python test scripts and validates their output.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL