You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jul 26, 2024. It is now read-only.
Eel is a little Python library for making simple Electron-like offline HTML/JS GUI apps, with full access to Python capabilities and libraries.
8
+
Paling is a updated version of Eel, the Python library for making simple Electron-like offline HTML/JS GUI apps, with full access to Python capabilities and libraries.
9
9
10
10
> **Eel hosts a local webserver, then lets you annotate functions in Python so that they can be called from Javascript, and vice versa.**
11
11
@@ -36,6 +36,8 @@ Eel is designed to take the hassle out of writing short and simple GUI applicati
36
36
37
37
## Intro
38
38
39
+
Eel has always been our favorite library for writing UI's in python, because it made it very simple to create a beautiful interface. Unfortunately the project has not been maintained, and now we are taking over.
40
+
39
41
There are several options for making GUI apps in Python, but if you want to use HTML/JS (in order to use jQueryUI or Bootstrap, for example) then you generally have to write a lot of boilerplate code to communicate from the Client (Javascript) side to the Server (Python) side.
40
42
41
43
The closest Python equivalent to Electron (to my knowledge) is [cefpython](https://github.com/cztomczak/cefpython). It is a bit heavy weight for what I wanted.
@@ -51,7 +53,7 @@ Join Eel's users and maintainers on [Discord](https://discord.com/invite/3nqXPFX
51
53
Install from pypi with `pip`:
52
54
53
55
```shell
54
-
pip install eel
56
+
pip install paling
55
57
```
56
58
57
59
To include support for HTML templating, currently using [Jinja2](https://pypi.org/project/Jinja2/#description):
@@ -85,8 +87,8 @@ Suppose you put all the frontend files in a directory called `web`, including yo
85
87
86
88
```python
87
89
import eel
88
-
aal.init('web')
89
-
aal.start('main.html')
90
+
paling.init('web')
91
+
paling.start('main.html')
90
92
```
91
93
92
94
This will start a webserver on the default settings (http://localhost:8000) and open a browser to http://localhost:8000/main.html.
@@ -95,7 +97,7 @@ If Chrome or Chromium is installed then by default it will open in that in App M
95
97
96
98
### App options
97
99
98
-
Additional options can be passed to `aal.start()` as keyword arguments.
100
+
Additional options can be passed to `paling.start()` as keyword arguments.
99
101
100
102
Some of the options include the mode the app is in (e.g. 'chrome'), the port the app runs on, the host name of the app, and adding additional command line flags.
101
103
@@ -105,30 +107,30 @@ As of Eel v0.12.0, the following options are available to `start()`:
105
107
-**port**, an int specifying what port to use for the Bottle server. Use `0` for port to be picked automatically. *Default: `8000`*.
106
108
-**block**, a bool saying whether or not the call to `start()` should block the calling thread. *Default: `True`*
107
109
-**jinja_templates**, a string specifying a folder to use for Jinja2 templates, e.g. `my_templates`. *Default: `None`*
108
-
-**cmdline_args**, a list of strings to pass to the command to start the browser. For example, we might add extra flags for Chrome; ```aal.start('main.html', mode='chrome-app', port=8080, cmdline_args=['--start-fullscreen', '--browser-startup-dialog'])```. *Default: `[]`*
110
+
-**cmdline_args**, a list of strings to pass to the command to start the browser. For example, we might add extra flags for Chrome; ```paling.start('main.html', mode='chrome-app', port=8080, cmdline_args=['--start-fullscreen', '--browser-startup-dialog'])```. *Default: `[]`*
109
111
-**size**, a tuple of ints specifying the (width, height) of the main window in pixels *Default: `None`*
110
112
-**position**, a tuple of ints specifying the (left, top) of the main window in pixels *Default: `None`*
111
113
-**geometry**, a dictionary specifying the size and position for all windows. The keys should be the relative path of the page, and the values should be a dictionary of the form `{'size': (200, 100), 'position': (300, 50)}`. *Default: {}*
112
114
-**close_callback**, a lambda or function that is called when a websocket to a window closes (i.e. when the user closes the window). It should take two arguments; a string which is the relative path of the page that just closed, and a list of other websockets that are still open. *Default: `None`*
113
-
-**app**, an instance of Bottle which will be used rather than creating a fresh one. This can be used to install middleware on the instance before starting eel, e.g. for session management, authentication, etc. If your `app` is not a Bottle instance, you will need to call `aal.register_eel_routes(app)` on your custom app instance.
115
+
-**app**, an instance of Bottle which will be used rather than creating a fresh one. This can be used to install middleware on the instance before starting eel, e.g. for session management, authentication, etc. If your `app` is not a Bottle instance, you will need to call `paling.register_eel_routes(app)` on your custom app instance.
114
116
-**shutdown_delay**, timer configurable for Eel's shutdown detection mechanism, whereby when any websocket closes, it waits `shutdown_delay` seconds, and then checks if there are now any websocket connections. If not, then Eel closes. In case the user has closed the browser and wants to exit the program. By default, the value of **shutdown_delay** is `1.0` second
115
117
116
118
117
119
118
120
### Exposing functions
119
121
120
-
In addition to the files in the frontend folder, a Javascript library will be served at `/aal.js`. You should include this in any pages:
122
+
In addition to the files in the frontend folder, a Javascript library will be served at `/paling.js`. You should include this in any pages:
aal.my_python_function(1, 2); // This calls the Python function that was decorated
142
+
paling.my_python_function(1, 2); // This calls the Python function that was decorated
141
143
```
142
144
143
145
Similarly, any Javascript functions which are exposed like this...
144
146
145
147
```javascript
146
-
aal.expose(my_javascript_function);
148
+
paling.expose(my_javascript_function);
147
149
functionmy_javascript_function(a, b, c, d) {
148
150
if (a < b) {
149
151
console.log(c * d);
@@ -155,13 +157,13 @@ can be called from the Python side like this...
155
157
156
158
```python
157
159
print('Calling Javascript...')
158
-
aal.my_javascript_function(1, 2, 3, 4) # This calls the Javascript function
160
+
paling.my_javascript_function(1, 2, 3, 4) # This calls the Javascript function
159
161
```
160
162
161
163
The exposed name can also be overridden by passing in a second argument. If your app minifies JavaScript during builds, this may be necessary to ensure that functions can be resolved on the Python side:
When passing complex objects as arguments, bear in mind that internally they are converted to JSON and sent down a websocket (a process that potentially loses information).
@@ -178,16 +180,16 @@ Putting this together into a **Hello, World!** example, we have a short HTML pag
178
180
<head>
179
181
<title>Hello, World!</title>
180
182
181
-
<!-- Include aal.js - note this file doesn't exist in the 'web' directory -->
@paling.expose# Expose this function to Javascript
210
212
defsay_hello_py(x):
211
213
print('Hello from %s'% x)
212
214
213
215
say_hello_py('Python World!')
214
-
aal.say_hello_js('Python World!') # Call a Javascript function
216
+
paling.say_hello_js('Python World!') # Call a Javascript function
215
217
216
-
aal.start('hello.html') # Start (this blocks and enters loop)
218
+
paling.start('hello.html') # Start (this blocks and enters loop)
217
219
```
218
220
219
221
If we run the Python script (`python hello.py`), then a browser window will open displaying `hello.html`, and we will see...
@@ -241,7 +243,7 @@ While we want to think of our code as comprising a single application, the Pytho
241
243
Eel supports two ways of retrieving _return values_ from the other side of the app, which helps keep the code concise.
242
244
243
245
To prevent hanging forever on the Python side, a timeout has been put in place for trying to retrieve values from
244
-
the JavaScript side, which defaults to 10000 milliseconds (10 seconds). This can be changed with the `_js_result_timeout` parameter to `aal.init`. There is no corresponding timeout on the JavaScript side.
246
+
the JavaScript side, which defaults to 10000 milliseconds (10 seconds). This can be changed with the `_js_result_timeout` parameter to `paling.init`. There is no corresponding timeout on the JavaScript side.
245
247
246
248
#### Callbacks
247
249
@@ -250,7 +252,7 @@ When you call an exposed function, you can immediately pass a callback function
250
252
For example, if we have the following function defined and exposed in Javascript:
251
253
252
254
```javascript
253
-
aal.expose(js_random);
255
+
paling.expose(js_random);
254
256
functionjs_random() {
255
257
returnMath.random();
256
258
}
@@ -263,10 +265,10 @@ def print_num(n):
263
265
print('Got this from Javascript:', n)
264
266
265
267
# Call Javascript function, and pass explicit callback function
266
-
aal.js_random()(print_num)
268
+
paling.js_random()(print_num)
267
269
268
270
# Do the same with an inline lambda as callback
269
-
aal.js_random()(lambdan: print('Got this from Javascript:', n))
271
+
paling.js_random()(lambdan: print('Got this from Javascript:', n))
270
272
```
271
273
272
274
(It works exactly the same the other way around).
@@ -278,19 +280,19 @@ In most situations, the calls to the other side are to quickly retrieve some pie
278
280
To synchronously retrieve the return value, simply pass nothing to the second set of brackets. So in Python we would write:
279
281
280
282
```python
281
-
n =aal.js_random()() # This immediately returns the value
283
+
n =paling.js_random()() # This immediately returns the value
282
284
print('Got this from Javascript:', n)
283
285
```
284
286
285
-
You can only perform synchronous returns after the browser window has started (after calling `aal.start()`), otherwise obviously the call will hang.
287
+
You can only perform synchronous returns after the browser window has started (after calling `paling.start()`), otherwise obviously the call will hang.
286
288
287
289
In Javascript, the language doesn't allow us to block while we wait for a callback, except by using `await` from inside an `async` function. So the equivalent code from the Javascript side would be:
288
290
289
291
```javascript
290
292
asyncfunctionrun() {
291
293
// Inside a function marked 'async' we can use the 'await' keyword.
292
294
293
-
let n =awaitaal.py_random()(); // Must prefix call with 'await', otherwise it's the same syntax
295
+
let n =awaitpaling.py_random()(); // Must prefix call with 'await', otherwise it's the same syntax
294
296
console.log("Got this from Python: "+ n);
295
297
}
296
298
@@ -307,20 +309,20 @@ In this example...
307
309
308
310
```python
309
311
import eel
310
-
aal.init('web')
312
+
paling.init('web')
311
313
312
314
defmy_other_thread():
313
315
whileTrue:
314
316
print("I'm a thread")
315
-
aal.sleep(1.0) # Use aal.sleep(), not time.sleep()
317
+
paling.sleep(1.0) # Use paling.sleep(), not time.sleep()
316
318
317
-
aal.spawn(my_other_thread)
319
+
paling.spawn(my_other_thread)
318
320
319
-
aal.start('main.html', block=False) # Don't block on this call
321
+
paling.start('main.html', block=False) # Don't block on this call
320
322
321
323
whileTrue:
322
324
print("I'm a main loop")
323
-
aal.sleep(1.0) # Use aal.sleep(), not time.sleep()
325
+
paling.sleep(1.0) # Use paling.sleep(), not time.sleep()
324
326
```
325
327
326
328
...we would then have three "threads" (greenlets) running;
@@ -344,7 +346,7 @@ Consult the [documentation for PyInstaller](http://PyInstaller.readthedocs.io/en
344
346
345
347
## Microsoft Edge
346
348
347
-
For Windows 10 users, Microsoft Edge (`aal.start(.., mode='edge')`) is installed by default and a useful fallback if a preferred browser is not installed. See the examples:
349
+
For Windows 10 users, Microsoft Edge (`paling.start(.., mode='edge')`) is installed by default and a useful fallback if a preferred browser is not installed. See the examples:
348
350
349
351
- A Hello World example using Microsoft Edge: [examples/01 - hello_world-Edge/](https://github.com/ChrisKnott/Eel/tree/master/examples/01%20-%20hello_world-Edge)
350
352
- Example implementing browser-fallbacks: [examples/07 - CreateReactApp/eel_CRA.py](https://github.com/ChrisKnott/Eel/tree/master/examples/07%20-%20CreateReactApp/eel_CRA.py)
0 commit comments