UNPKG

@badc0d3/piece-python-runner

Version:

Run Python code with imports in Activepieces

349 lines (265 loc) 9.48 kB
# Python Code Runner for Activepieces A powerful Activepieces piece that allows you to execute Python code with support for external libraries and imports. ## Features - 🐍 **Execute Python Code**: Run Python scripts directly in your workflows - 📦 **Package Management**: Install and use any Python package from PyPI - 🔒 **Two Execution Modes**: - Standard: Fast execution with virtual environments - Sandboxed: Secure Docker-based execution with resource limits -**Fast Execution**: Reuse Python environment when possible - 🎯 **Error Handling**: Clear error messages and stack traces - 📊 **JSON Output**: Easy integration with other workflow steps ### UI Note Currently, Activepieces uses a multi-line text box for code input. While it doesn't have syntax highlighting like a full code editor, you can: - Write your code in your favorite editor and paste it - Use proper indentation (the text box preserves formatting) - Test your code locally first, then paste into Activepieces ## Installation 1. Clone this repository to your Activepieces pieces directory: ```bash cd piece-python-runner ``` 2. Install dependencies: ```bash npm install ``` 3. Build the piece: ```bash npm run build ``` 4. Deploy to your Activepieces instance (follow your instance's deployment guide) ## Usage ### Basic Example ```python import json # Simple calculation result = 2 + 2 data = {"result": result, "message": "Hello from Python!"} print(json.dumps(data)) ``` ### Using External Libraries In the "Requirements" field, list the packages you need (one per line): ``` requests pandas numpy matplotlib ``` Then use them in your code: ```python import requests import pandas as pd import numpy as np import json # Fetch data from an API response = requests.get('https://api.example.com/data') data = response.json() # Process with pandas df = pd.DataFrame(data) mean_value = df['value'].mean() # Use numpy for calculations values = np.array(df['value']) std_dev = np.std(values) result = { "mean": mean_value, "std_dev": std_dev, "count": len(df) } print(json.dumps(result)) ``` ### Data Processing Example ```python import pandas as pd import json from datetime import datetime # Create sample data sales_data = { 'date': ['2024-01-01', '2024-01-02', '2024-01-03'], 'product': ['A', 'B', 'A'], 'quantity': [10, 15, 20], 'price': [100, 200, 100] } # Process with pandas df = pd.DataFrame(sales_data) df['total'] = df['quantity'] * df['price'] df['date'] = pd.to_datetime(df['date']) # Calculate summary statistics summary = { 'total_revenue': float(df['total'].sum()), 'average_quantity': float(df['quantity'].mean()), 'products_sold': df['product'].nunique(), 'date_range': { 'start': df['date'].min().strftime('%Y-%m-%d'), 'end': df['date'].max().strftime('%Y-%m-%d') } } print(json.dumps(summary, indent=2)) ``` ### Web Scraping Example ```python import requests from bs4 import BeautifulSoup import json # Scrape a website url = 'https://example.com' response = requests.get(url) soup = BeautifulSoup(response.content, 'html.parser') # Extract data title = soup.find('title').text if soup.find('title') else 'No title' links = [a.get('href') for a in soup.find_all('a', href=True)] result = { 'title': title, 'link_count': len(links), 'first_5_links': links[:5] } print(json.dumps(result, indent=2)) ``` ## Configuration Options ### Python Code The main Python code to execute. Supports all standard Python features including imports, functions, classes, etc. ### Requirements List of Python packages to install before execution. Format: - One package per line - Supports version specifications (e.g., `requests==2.28.0`) - Supports git URLs for custom packages ### Timeout Maximum execution time in seconds (default: 30). Prevents infinite loops and long-running processes. ### Python Version Choose from: - Python 3 (Default) - Uses system default Python 3 - Python 3.9 - Python 3.10 - Python 3.11 ### Capture Output When enabled, returns separate stdout and stderr in the result object. ## Output Format The action returns an object with the following structure: ```json { "success": true, "output": { // Your parsed JSON output or string output }, "stdout": "Full stdout content (if capture output is enabled)", "stderr": "Full stderr content (if capture output is enabled)", "executionTime": "2024-01-01T12:00:00.000Z" } ``` On error: ```json { "success": false, "error": "Error message", "stdout": "Stdout before error", "stderr": "Stderr content", "code": "Error code", "executionTime": "2024-01-01T12:00:00.000Z" } ``` ## Security Considerations ### Standard Version - Runs in isolated virtual environments - Each execution gets a fresh environment - Temporary files are cleaned up after execution - Resource limits enforced by timeout ### Sandboxed Version - Runs in Docker containers - Memory limited to 512MB - CPU limited to 50% of one core - Network access can be restricted - Complete isolation from host system - Runs as non-root user for enhanced security ## Best Practices 1. **Always use virtual environments**: This piece automatically creates one for each execution 2. **Return JSON when possible**: Makes it easier to use output in subsequent workflow steps 3. **Handle errors gracefully**: Use try-except blocks in your Python code 4. **Be mindful of timeouts**: Long-running operations should be broken into smaller steps 5. **Clean up resources**: The piece automatically cleans up, but close files/connections in your code 6. **Use specific package versions**: Pin versions in requirements for reproducibility ## Docker Deployment ### Running in Docker When deploying Activepieces in Docker, the Python Code Runner adapts to the container environment: 1. **Automatic Detection**: The piece detects Docker environments and skips virtual environment creation 2. **System Python**: Uses the container's Python installation directly 3. **Package Installation**: Installs packages with `--user` flag when pip is available ### Docker Setup Requirements For the **standard Python Code Runner** to work in Docker, ensure your container has: ```dockerfile # Example Dockerfile additions RUN apt-get update && apt-get install -y \ python3 \ python3-pip \ && rm -rf /var/lib/apt/lists/* ``` ### Recommended: Use Sandboxed Version For Docker deployments, we **strongly recommend** using the **"Run Python Code (Sandboxed)"** action instead because: - It runs Python in a separate container with all dependencies pre-installed - No need to modify your Activepieces Docker image - Better isolation and security - Consistent environment across all executions - Automatically pulls the python:slim image if not present **Important**: To use the sandboxed version in Docker, you must mount the Docker socket: ```yaml # docker-compose.yml example services: activepieces: image: activepieces/activepieces volumes: - /var/run/docker.sock:/var/run/docker.sock # Required for sandboxed Python runner # ... other configuration ``` Or with Docker run: ```bash docker run -v /var/run/docker.sock:/var/run/docker.sock activepieces/activepieces ``` **Security Note**: Mounting the Docker socket gives the container access to Docker. Only do this in trusted environments. ### Minimal Docker Image If you're using a minimal Docker image without pip: 1. **Option 1**: Install pip in your Dockerfile (shown above) 2. **Option 2**: Use the sandboxed version 3. **Option 3**: Only use Python standard library (no external packages) ## Troubleshooting ### Common Issues 1. **Import Error**: Package not found - Make sure to list the package in the Requirements field - Check the package name is correct (case-sensitive) 2. **Timeout Error**: Execution exceeded timeout - Increase the timeout value - Optimize your code for better performance - Consider breaking into smaller steps 3. **"connect ENOENT /var/run/docker.sock"** (Sandboxed version) - This means Docker socket is not accessible - If running Activepieces in Docker, mount the socket: `-v /var/run/docker.sock:/var/run/docker.sock` - Alternatively, use the standard (non-sandboxed) version - Ensure Docker is installed and running on the host 4. **"No module named pip"** (Standard version) - Install pip in your environment: `apt-get install python3-pip` - Or use the sandboxed version which includes pip - Or use only Python standard library (no external packages) 5. **Virtual environment creation fails** - The piece automatically detects Docker and skips venv creation - In minimal containers, use the sandboxed version instead - Or ensure python3-venv is installed: `apt-get install python3-venv` 6. **JSON Parse Error**: Output is not valid JSON - Ensure you're using `json.dumps()` for output - Check for print statements that might interfere ## Development ### Building from Source ```bash # Install dependencies npm install # Build the piece npm run build # Run tests (if available) npm test ``` ### Contributing 1. Fork the repository 2. Create a feature branch 3. Make your changes 4. Add tests if applicable 5. Submit a pull request ## License This piece is distributed under the same license as Activepieces. ## Support For issues and feature requests, please open an issue in the repository or contact the Activepieces community.