Skip to content

Commit 945a68b

Browse files
committed
Adding python-web docs
1 parent fa18345 commit 945a68b

File tree

1 file changed

+242
-0
lines changed

1 file changed

+242
-0
lines changed

docs/python-web.md

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# Cross-Platform Python Companion for Flutter
2+
3+
This guide explains how to create and use a Python companion application that works across different platforms (Web, Desktop) using the serious_python package.
4+
5+
## Setup
6+
7+
### Project Structure
8+
```
9+
your_flutter_project/
10+
├── python_companion/
11+
│ ├── desktop/
12+
│ │ ├── __init__.py
13+
│ │ └── companion_server.py # Flask server for desktop
14+
│ ├── web/
15+
│ │ ├── __init__.py
16+
│ │ └── command_handler.py # Command handling for web
17+
│ ├── functionality/
18+
│ │ ├── __init__.py
19+
│ │ └── your_functions.py # Shared functionality
20+
│ ├── requirements/
21+
│ │ ├── base.txt # Shared dependencies
22+
│ │ ├── desktop.txt # Desktop-specific requirements
23+
│ │ └── web.txt # Web-specific (Pyodide) requirements
24+
│ ├── python_companion_desktop.py # Desktop entry point
25+
│ └── python_companion_web.py # Web entry point
26+
```
27+
28+
### Requirements Files
29+
30+
```txt
31+
# requirements/base.txt
32+
numpy>=1.20.0
33+
scipy>=1.7.0
34+
35+
# requirements/web.txt
36+
-r base.txt
37+
# Only Pyodide-compatible versions
38+
h5py==3.8.0
39+
40+
# requirements/desktop.txt
41+
-r base.txt
42+
flask>=2.0.0
43+
h5py==3.9.0
44+
```
45+
46+
### Implementation
47+
48+
1. Desktop Implementation (Flask Server):
49+
```python
50+
# desktop/companion_server.py
51+
from flask import Flask, request, jsonify
52+
import functionality
53+
54+
app = Flask(__name__)
55+
56+
@app.route('/your_endpoint', methods=['POST'])
57+
def your_endpoint():
58+
result = functionality.your_function(request.json)
59+
return jsonify(result)
60+
61+
def run_server():
62+
app.run(port=50001, debug=False, use_reloader=False)
63+
```
64+
65+
2. Web Implementation (Pyodide):
66+
```python
67+
# web/command_handler.py
68+
import json
69+
import functionality
70+
71+
_command_functions = {
72+
"your_command": lambda data: functionality.your_function(data),
73+
}
74+
75+
def handle_command(command: str, data):
76+
command_function = _command_functions.get(command)
77+
try:
78+
loaded_data = json.loads(data)
79+
except:
80+
loaded_data = data
81+
return command_function(data)
82+
```
83+
84+
3. Shared Functionality:
85+
```python
86+
# functionality/your_functions.py
87+
88+
def your_function(json_data):
89+
# Your implementation
90+
return {"result": "success"}
91+
```
92+
93+
4. Entry Points:
94+
```python
95+
# python_companion_desktop.py
96+
from desktop import run_server
97+
98+
if __name__ == '__main__':
99+
run_server()
100+
101+
# python_companion_web.py
102+
import os
103+
from web import handle_command
104+
105+
if __name__ == '__main__':
106+
command = os.environ.get("PYODIDE_COMMAND", "")
107+
data = os.environ.get("PYODIDE_DATA", None)
108+
pyodide_result = handle_command(command, data)
109+
```
110+
111+
### Packaging
112+
113+
Package your Python companion for different platforms:
114+
115+
```bash
116+
# For Web (Pyodide)
117+
dart run serious_python:main package \
118+
--asset assets/python_companion.zip python_companion/ \
119+
-p Pyodide \
120+
--requirements "-r,python_companion/requirements/web.txt"
121+
122+
# For Desktop (Linux)
123+
dart run serious_python:main package \
124+
--asset assets/python_companion.zip python_companion/ \
125+
-p Linux \
126+
--requirements "-r,python_companion/requirements/desktop.txt"
127+
```
128+
129+
## Usage in Flutter
130+
131+
1. Add serious_python to your pubspec.yaml:
132+
```yaml
133+
dependencies:
134+
serious_python: ^latest_version
135+
```
136+
137+
2. Create a service class:
138+
```dart
139+
class PythonCompanionService {
140+
Future<Either<Exception, Map<String, dynamic>>> callPythonFunction(List<double> data);
141+
}
142+
143+
class PythonCompanionServiceWeb implements PythonCompanionService {
144+
Future<Either<Exception, Map<String, dynamic>>> callPythonFunction(List<double> data) async {
145+
final String? result = await SeriousPython.run(
146+
'assets/python_companion.zip',
147+
appFileName: 'python_companion_web.py',
148+
modulePaths: ['python_companion/web', 'python_companion/functionality'],
149+
environmentVariables:
150+
{
151+
'PYODIDE_COMMAND': 'your_command',
152+
'PYODIDE_DATA': jsonEncode({'data': data})
153+
},
154+
sync: true,
155+
);
156+
157+
if (result == null || result.isEmpty) {
158+
return left(Exception('Failed to execute Python function'));
159+
}
160+
161+
return right(jsonDecode(result));
162+
}
163+
}
164+
165+
class PythonCompanionServiceDesktop implements PythonCompanionService {
166+
@override
167+
Future<void> startServer() async {
168+
try {
169+
// Start the Python server
170+
await SeriousPython.run(
171+
'assets/python_companion.zip',
172+
appFileName: 'python_companion_desktop.py',
173+
);
174+
175+
// Wait for server to be ready, e.g. by checking the health endpoint
176+
await _waitForServer();
177+
_isServerRunning = true;
178+
} catch (e) {
179+
throw Exception('Failed to start Python server: $e');
180+
}
181+
}
182+
183+
@override
184+
Future<Either<Exception, Map<String, dynamic>>> callPythonFunction(List<double> data) async {
185+
try {
186+
final response = await http.post(
187+
Uri.parse('$_baseUrl/your_endpoint'),
188+
headers: {'Content-Type': 'application/json'},
189+
body: jsonEncode({'data': data}),
190+
);
191+
192+
if (response.statusCode != 200) {
193+
return left(Exception('Server error: ${response.statusCode}'));
194+
}
195+
196+
return right(jsonDecode(response.body));
197+
} catch (e) {
198+
return left(Exception('Error calling Python function: $e'));
199+
}
200+
}
201+
}
202+
```
203+
204+
3. Use in your Flutter app:
205+
```dart
206+
final pythonService = PythonCompanionService();
207+
208+
void yourFunction() async {
209+
final result = await pythonService.callPythonFunction([1.0, 2.0, 3.0]);
210+
result.fold(
211+
(error) => print('Error: $error'),
212+
(success) => print('Success: $success'),
213+
);
214+
}
215+
```
216+
217+
## Important Notes
218+
219+
1. **Web Compatibility**: Ensure all Python packages used in web implementation are [Pyodide-compatible](https://pyodide.org/en/stable/usage/packages-in-pyodide.html).
220+
221+
2. **Package Versions**: Use platform-specific package versions when needed (e.g., different h5py versions for web and desktop).
222+
223+
3. **Error Handling**: Implement proper error handling in both Python and Dart code.
224+
225+
4. **Data Transfer**: Use JSON for data transfer between Flutter and Python.
226+
227+
5. **Resource Management**: Properly manage resources (close files, connections, etc.).
228+
229+
## Troubleshooting
230+
231+
1. **Module Import Issues**: Ensure correct module paths and dependencies.
232+
2. **Platform Compatibility**: Check package compatibility for each platform.
233+
3. **Port Conflicts**: For desktop, ensure the Flask server port (50001) is available.
234+
4. **Memory Management**: Be mindful of memory usage, especially with large data operations.
235+
236+
## Best Practices
237+
238+
1. Keep shared functionality platform-independent
239+
2. Implement proper error handling and logging
240+
3. Use type hints and documentation
241+
4. Follow platform-specific conventions
242+
5. Test on all target platforms

0 commit comments

Comments
 (0)