π PyEngine Desktop - Embedded Python Runtime for Flutter
The ultimate Flutter plugin for embedded Python scripting and automation on desktop platforms. Seamlessly integrate Python interpreter, execute scripts, run interactive REPL sessions, and manage packages - all within your Flutter desktop applications.
π Perfect for: Data science apps, automation tools, machine learning integrations, scripting interfaces, educational platforms, and any desktop app requiring Python backend processing.
π― Production Ready - Fully tested on Windows, macOS & Linux
β¨ Key Features
- π Embedded Python Runtime: Zero-dependency Python 3.11 interpreter with automatic distribution management
- π₯οΈ Cross-Platform Desktop: Native support for Windows x64, macOS x64, and Linux x64
- π Python Script Execution: Real-time stdout/stderr streaming with process control
- π Interactive Python REPL: Full-featured Python shell with command history and output capture
- π¦ Pip Package Management: Install NumPy, Pandas, Requests, and any PyPI package
- π Isolated Environment: App-specific Python installation prevents system conflicts
- π Zero Configuration: One-line initialization with automatic runtime setup
- β‘ High Performance: Cached runtime for instant subsequent launches
- π οΈ Developer Friendly: Comprehensive error handling and debugging support
Supported Platforms
Platform | Support | Architecture | Tested |
---|---|---|---|
Windows | β | x64 | β |
macOS | β | x64 | β |
Linux | β | x64 | β |
Android | β | - | - |
iOS | β | - | - |
Web | β | - | - |
π― Use Cases & Applications
Perfect for developers building:
π Data Science & Analytics
- Business Intelligence Tools: Real-time data processing with Pandas and NumPy
- Data Visualization Apps: Interactive charts using Matplotlib and Seaborn
- Scientific Computing: Mathematical modeling and statistical analysis
- Machine Learning Interfaces: Model training and inference with scikit-learn, TensorFlow
π€ Automation & Scripting
- Desktop Automation Tools: System administration and task automation
- File Processing Applications: Batch operations, format conversions, data migration
- API Integration Platforms: REST API clients, web scraping tools
- DevOps Dashboards: Deployment scripts, monitoring tools, CI/CD interfaces
π Educational & Learning
- Python Learning Platforms: Interactive coding environments and tutorials
- STEM Education Apps: Mathematical computing, physics simulations
- Code Playgrounds: Live Python coding with instant feedback
- Algorithm Visualization: Data structures and algorithms teaching tools
π§ Developer Tools & IDEs
- Code Editors: Python syntax highlighting, code completion
- Testing Frameworks: Automated testing interfaces, test runners
- Database Management: SQL query builders, data migration tools
- Configuration Managers: Settings editors, environment management
π’ Enterprise Applications
- Report Generators: Automated PDF/Excel report creation
- System Monitoring: Performance dashboards, log analysis
- Integration Platforms: ERP connectors, data synchronization
- Workflow Automation: Business process automation, approval systems
Installation
Add this to your package's pubspec.yaml
file:
dependencies:
py_engine_desktop: ^1.0.0
Then run:
flutter pub get
π Important: macOS Configuration
For macOS apps, you MUST disable sandbox mode to allow Python executable execution.
In your Flutter macOS project, update the following files:
macos/Runner/DebugProfile.entitlements
and macos/Runner/Release.entitlements
Change:
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
To:
<dict>
<key>com.apple.security.app-sandbox</key>
<false/>
</dict>
β οΈ Note: Disabling sandbox mode is required for executing Python processes. This is a limitation of macOS security model when running external executables. Without this change, you'll get
ProcessException: Operation not permitted
errors.
Quick Start
1. Add dependency
Add this to your pubspec.yaml
:
dependencies:
py_engine_desktop: ^1.0.0
2. Import and Initialize
import 'package:py_engine_desktop/py_engine_desktop.dart';
class MyPythonApp extends StatefulWidget {
@override
_MyPythonAppState createState() => _MyPythonAppState();
}
class _MyPythonAppState extends State<MyPythonApp> {
bool _initialized = false;
@override
void initState() {
super.initState();
_initializePython();
}
Future<void> _initializePython() async {
try {
await PyEngineDesktop.init();
setState(() => _initialized = true);
print('Python engine ready!');
} catch (e) {
print('Failed to initialize: $e');
}
}
}
3. Run Python Scripts
Future<void> runPythonScript() async {
if (!_initialized) return;
// Create a simple Python script
final script = '''
import math
print("Hello from Python!")
print(f"Pi = {math.pi}")
for i in range(5):
print(f"Count: {i}")
''';
// Write script to temp file
final tempDir = await getTemporaryDirectory();
final scriptFile = File(path.join(tempDir.path, 'my_script.py'));
await scriptFile.writeAsString(script);
// Execute the script
final pythonScript = await PyEngineDesktop.startScript(scriptFile.path);
// Listen to output
pythonScript.stdout.listen((line) {
print('Python Output: $line');
});
pythonScript.stderr.listen((line) {
print('Python Error: $line');
});
// Wait for completion
await pythonScript.exitCode;
print('Script completed!');
}
4. Interactive Python REPL
PythonRepl? _repl;
Future<void> startInteractivePython() async {
if (!_initialized) return;
_repl = await PyEngineDesktop.startRepl();
// Listen to all output
_repl!.output.listen((output) {
print('REPL: $output');
});
// Send some commands
_repl!.send('import numpy as np');
_repl!.send('arr = np.array([1, 2, 3, 4, 5])');
_repl!.send('print("Array:", arr)');
_repl!.send('print("Mean:", np.mean(arr))');
}
void sendCommand(String command) {
if (_repl != null) {
_repl!.send(command);
}
}
5. Package Management
Future<void> setupPythonPackages() async {
if (!_initialized) return;
// Install essential packages
await PyEngineDesktop.pipInstall('numpy');
await PyEngineDesktop.pipInstall('pandas');
await PyEngineDesktop.pipInstall('requests');
print('Packages installed successfully!');
}
// Test if packages work
Future<void> testPackages() async {
final repl = await PyEngineDesktop.startRepl();
repl.output.listen((output) => print(output));
// Test numpy
repl.send('import numpy as np');
repl.send('print("NumPy version:", np.__version__)');
// Test pandas
repl.send('import pandas as pd');
repl.send('df = pd.DataFrame({"A": [1,2,3], "B": [4,5,6]})');
repl.send('print(df)');
repl.stop();
}
6. Complete Widget Example
class PythonConsole extends StatefulWidget {
@override
_PythonConsoleState createState() => _PythonConsoleState();
}
class _PythonConsoleState extends State<PythonConsole> {
final TextEditingController _controller = TextEditingController();
final List<String> _output = [];
PythonRepl? _repl;
bool _initialized = false;
@override
void initState() {
super.initState();
_initPython();
}
Future<void> _initPython() async {
await PyEngineDesktop.init();
_repl = await PyEngineDesktop.startRepl();
_repl!.output.listen((line) {
setState(() => _output.add(line));
});
setState(() => _initialized = true);
}
void _sendCommand() {
final command = _controller.text.trim();
if (command.isNotEmpty && _repl != null) {
setState(() => _output.add('>>> $command'));
_repl!.send(command);
_controller.clear();
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: Container(
padding: EdgeInsets.all(8),
color: Colors.black,
child: ListView.builder(
itemCount: _output.length,
itemBuilder: (context, index) => Text(
_output[index],
style: TextStyle(color: Colors.green, fontFamily: 'monospace'),
),
),
),
),
if (_initialized)
Padding(
padding: EdgeInsets.all(8),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(hintText: 'Enter Python command...'),
onSubmitted: (_) => _sendCommand(),
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: _sendCommand,
),
],
),
),
],
);
}
@override
void dispose() {
_repl?.stop();
super.dispose();
}
}
API Reference
PyEngineDesktop
Main class providing static methods for Python engine management.
PyEngineDesktop.init()
Purpose: Initializes the Python engine by extracting and setting up the embedded Python runtime.
What it does:
- Extracts Python runtime from bundled assets (first run only)
- Sets up Python executable with proper permissions
- Configures site-packages directory for pip installations
- Caches runtime for faster subsequent launches
// Basic initialization
await PyEngineDesktop.init();
// With error handling
try {
await PyEngineDesktop.init();
print('Python engine ready!');
} catch (e) {
if (e is UnsupportedError) {
print('Platform not supported');
} else {
print('Initialization failed: $e');
}
}
PyEngineDesktop.startScript(String scriptPath)
Purpose: Executes a Python script file and returns a PythonScript
object for monitoring.
What it does:
- Validates script file exists before execution
- Starts Python process with the script
- Automatically includes site-packages in Python path
- Returns
PythonScript
object for output monitoring and control
// Basic script execution
final script = await PyEngineDesktop.startScript('/path/to/script.py');
// Listen to output streams
script.stdout.listen((line) => print('Output: $line'));
script.stderr.listen((line) => print('Error: $line'));
// Wait for completion
final exitCode = await script.exitCode;
print('Script finished with code: $exitCode');
// Or stop manually if needed
script.stop();
PyEngineDesktop.startRepl()
Purpose: Starts an interactive Python REPL (Read-Eval-Print Loop) session.
What it does:
- Launches Python in interactive mode using
code.interact()
- Automatically includes site-packages for installed packages
- Combines stdout/stderr into single output stream
- Allows sending commands via
send()
method
// Start REPL and send commands
final repl = await PyEngineDesktop.startRepl();
// Listen to all output (both results and prompts)
repl.output.listen((output) => print(output));
// Send Python commands
repl.send('print("Hello Python!")');
repl.send('x = 5 + 3');
repl.send('print(f"Result: {x}")');
// Send multi-line code
repl.send('for i in range(3):');
repl.send(' print(f"Count: {i}")');
// Stop when done
repl.stop();
PyEngineDesktop.pipInstall(String package)
/ PyEngineDesktop.pipUninstall(String package)
Purpose: Manages Python packages using pip package manager.
What it does:
pipInstall
: Downloads and installs Python packages from PyPIpipUninstall
: Removes installed Python packages- Automatically downloads and sets up pip if not available
- Installs packages to embedded Python's site-packages directory
// Install packages
try {
await PyEngineDesktop.pipInstall('numpy');
await PyEngineDesktop.pipInstall('requests==2.28.1'); // Specific version
print('Packages installed successfully');
} catch (e) {
print('Installation failed: $e');
}
// Uninstall packages
try {
await PyEngineDesktop.pipUninstall('numpy');
print('Package uninstalled successfully');
} catch (e) {
print('Uninstallation failed: $e');
}
PyEngineDesktop.pythonPath
Purpose: Gets the absolute path to the embedded Python executable.
What it does:
- Returns full path to Python executable after initialization
- Throws
StateError
if called beforeinit()
- Path points to embedded Python runtime, not system Python
// Get Python executable path
await PyEngineDesktop.init();
final pythonPath = PyEngineDesktop.pythonPath;
print('Python executable: $pythonPath');
// Output example: C:\Users\...\AppData\Roaming\py_engine_desktop\python\python.exe
PyEngineDesktop.stopScript(PythonScript script)
Purpose: Stops a running Python script process.
What it does:
- Terminates the script process immediately
- Closes output streams
- Safe to call multiple times
final script = await PyEngineDesktop.startScript('script.py');
// ... later
await PyEngineDesktop.stopScript(script);
// Or use script.stop() directly
PyEngineDesktop.stopRepl(PythonRepl repl)
Purpose: Stops a running Python REPL session.
What it does:
- Terminates the REPL process
- Closes output streams
- Safe to call multiple times
final repl = await PyEngineDesktop.startRepl();
// ... later
await PyEngineDesktop.stopRepl(repl);
// Or use repl.stop() directly
PythonScript
Object returned by startScript()
representing a running Python script.
Properties:
Stream<String> stdout
- Script's standard output (line by line)Stream<String> stderr
- Script's error output (line by line)Process process
- Underlying Dart process objectFuture<int> exitCode
- Completes when script finishes with exit code
Methods:
void stop()
- Terminates the script immediately
PythonRepl
Object returned by startRepl()
representing an interactive Python session.
Properties:
Stream<String> output
- Combined stdout/stderr output streamProcess process
- Underlying Dart process objectFuture<int> exitCode
- Completes when REPL session ends
Methods:
void send(String code)
- Sends Python code to executevoid stop()
- Terminates the REPL session
Example Usage
Check out the example directory for a complete demo application that shows:
- Python engine initialization
- Running Python scripts with output display
- Interactive REPL with command input
- Installing and testing NumPy package
How It Works
Python Runtime Distribution
The plugin automatically downloads portable Python distributions:
- Windows: Embeddable Python distribution (python.org)
- macOS/Linux: Standalone Python builds (python-build-standalone)
File Locations
Python runtimes are extracted to platform-specific application support directories:
- Windows:
%AppData%/py_engine_desktop/python
- macOS:
~/Library/Application Support/py_engine_desktop/python
- Linux:
~/.local/share/py_engine_desktop/python
First Run Setup
On first initialization:
- Detects the current platform
- Extracts the appropriate Python runtime from assets
- Sets up the Python environment
- Subsequent runs use the cached Python installation
Error Handling
The plugin provides comprehensive error handling:
try {
await PyEngineDesktop.init();
} catch (e) {
if (e is UnsupportedError) {
print('Platform not supported: $e');
} else {
print('Initialization failed: $e');
}
}
Limitations
- Desktop Only: Only works on desktop platforms (Windows, macOS, Linux)
- Single Architecture: Currently supports x64 architectures only
- Python Version: Uses Python 3.11.x
- Size: Python runtimes add ~10-30MB to your app's size
- First Run: Initial setup requires extracting Python runtime (one-time delay)
Performance & Size
Platform | Runtime Size | First Init Time |
---|---|---|
Windows | ~15MB | 2-5 seconds |
macOS | ~25MB | 3-7 seconds |
Linux | ~30MB | 3-8 seconds |
Note: Python runtime is cached after first initialization. Subsequent app launches are instant.
Development
Building from Source
git clone https://github.com/NagarChinmay/py_engine_desktop.git
cd py_engine_desktop
flutter pub get
cd example
flutter run
Running Tests
flutter test
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Issues & Support
- π Bug Reports: GitHub Issues
- π‘ Feature Requests: GitHub Issues
- π Documentation: Check the example for complete usage
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
See CHANGELOG.md for a list of changes.
π Keywords & SEO
Flutter Python Plugin | Desktop Python Runtime | Embedded Python Interpreter | Python Script Execution | Interactive Python REPL | Flutter Desktop Automation | Python Package Management | Cross-Platform Python | Flutter Data Science | Machine Learning Flutter | Python Integration Flutter | Desktop Python Tools | Flutter Scripting | Python Backend Flutter | Educational Python Apps
Popular searches: flutter python, python desktop app, embedded python runtime, flutter scripting, python automation, data science flutter, machine learning desktop app, python repl flutter, cross-platform python, desktop python integration