Posted on: 2021-04-13
Let's eel (Vol.1 Basics)
15 minutes read (just reading not understanding)
- What is eel?
- Installing eel
- Let's code
- App icon
- Possible errors
- No chrome?
- Eelslapsπ
- What were those ()()
- Make a single executable file
- Some Projects with eel
What is eel?
Eel is a powerful Python library created by Chris Knott that allows you to communicate between Javascript and Python easily.
An HTML front-end with the Python backend, what do you want more?!
Installing eel
just simply open the command prompt or terminal and run this command pip install Eel
.
if have any problem make sure you have pip installed. if pip didn't install, run this command on terminal python -m pip install -U pip
.
Let's code
I divided it into 4 main parts:
- Calling a Python function from Javascript
- Getting returned value from a Python function called by Javascript
- Calling a Javascript function from Python
- Getting returned value from a Javascript function called in Python
Part 1 Calling a Python function from Javascript
First, make these files as you see below.
# letsEel.py
import eel
eel.init('.//webPageFolder') # path of the webpage folder
# codes
eel.start('index.html') # html file name
you should initialize the app eel.init('<path to the webpage folder>')
and at the end of the file start it by eel.start('<just html file name>')
. Now the Python file is ready.
<!-- webPageFolder/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<script type="text/javascript" src="eel.js"></script>
<title>Let's Eel</title>
</head>
<body>
<script src="app.js"></script>
</body>
</html>
The HTML file is pretty straight forward, just 3 things you should do:
- link the stylesheet
<link rel="stylesheet" href="styles.css">
- add the Javascript at the end
<script src="app.js"></script>
- and the most important thing is this tag
<script type="text/javascript" src="eel.js"></script>
even if you don't have the file namedeel.js
but you should add this to the head section and if you don't the app will crash.
/* webPageFolder/styles.css */
body {
background-color: #d3d6db;
font-family: Arial, Helvetica, sans-serif;
}
.textInput {
background-color: #d3d6db;
color: #303841;
padding: 10px;
margin-right: 5px;
border-radius: 2px;
border: 2px solid #303841;
outline: none;
font-size: large;
}
.buttonInput {
background-color: #303841;
color: #d3d6db;
padding: 10px;
border-radius: 2px;
border: 2px solid #303841;
outline: none;
transition-duration: 1s;
font-size: large;
}
.buttonInput:hover {
background-color: #be3144;
color: #d3d6db;
padding: 10px;
border-radius: 2px;
border: 2px solid #be3144;
outline: none;
transition-duration: 1s;
cursor: pointer;
}
.formJsToPy {
padding-top: 20px;
padding-bottom: 20px;
display: flex;
justify-content: center;
align-items: center;
}
hr {
color: #303841;
padding: 0px;
border: 3px solid #be3144;
border-top: 0px;
}
h4,
h5,
p {
color: #303841;
text-align: center;
padding-bottom: 0px;
margin-bottom: 0px;
}
h1 {
padding-top: 50px;
text-align: center;
}
it's just some style.
// webPageFolder/app.js
Leave the Javascript file empty for now.
Now if you run the Python file you will see something like this: (You know how to run a Python file!? if you don't ask in comments)
Now let's add an input box to get data from the user and display it on the Python terminal.
<!-- webPageFolder/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<script type="text/javascript" src="eel.js"></script>
<title>Let's Eel</title>
</head>
<body>
<h1>Let's Eel</h1>
<h4>Send data to python </h4>
<div class="formJsToPy">
<input class="textInput" type="text" id="theFirstInput">
<input class="buttonInput" type="button" onclick="SendDataToPython()" value="Send" id="theBtn">
</div>
<script src="app.js"></script>
</body>
</html>
the important part is these two lines:
<input class="textInput" type="text" id="theFirstInput">
<input class="buttonInput" type="button" onclick="SendDataToPython()" value="Send" id="theBtn">
The first one is just an input to get data.
and the second one is a button that has an attribute called onclick that is a function and runs when you click on the button. and we handle it on the Javascript side.
// webPageFolder/app.js
function SendDataToPython() { // this will call a python function directly from here
const input = document.getElementById("theFirstInput").value;
eel.printFromPython(input); // eel.thePythonFunctionToCall
}
- we select the input field's value with
document.getElementById("theFirstInput").value
- then call a Python function(will define it later) with the input value.
So, let's jump into Python.
# letsEel.py
import eel
eel.init('.//webPageFolder') # path of the webpage folder
@eel.expose
def printFromPython(dataFromJs):
print(dataFromJs)
eel.start('index.html') # html file name
- before any Python function that we want to call from js, we should add
@eel.expose
. (if you don't it will not work) - then we define a smile function that prints something on the terminal.
Now if you run the Python this window will open:
Now write something in the input and click the Send button.
This is basically what we have done:
Part 2 Getting returned value from a Python function called by Javascript
Now let's get some data from Python and display it, but first, we should tell the Python that we want something. and we do that by pressing a button.
<!-- webPageFolder/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<script type="text/javascript" src="eel.js"></script>
<title>Let's Eel</title>
</head>
<body>
<h1>Let's Eel</h1>
<h4>Send data to python </h4>
<div class="formJsToPy">
<input class="textInput" type="text" id="theFirstInput">
<input class="buttonInput" type="button" onclick="SendDataToPython()" value="Send" id="theBtn">
</div>
<hr>
<h4>Getting data from Python </h4>
<div class="formJsToPy">
<input class="buttonInput" type="button" onclick="getDataFromPython()" value="Get From Python" id="theBtnGet">
</div>
<p id="showDataFromPython"></p>
<script src="app.js"></script>
</body>
</html>
So we add a button that has onclick="getDataFromPython()"
that runs a Javascript function when you click on it.
and there is a p
tag to show the result, but now it is empty.
// webPageFolder/app.js
function SendDataToPython() { // this will call a python function directly from here
const input = document.getElementById("theFirstInput").value;
eel.printFromPython(input); // eel.thePythonFunctionToCall
}
async function getDataFromPython() { // this will also call another function from python and get returned result
let returnedValueFromPython = await eel.sendDataToJavaScript()();
document.getElementById("showDataFromPython").innerText = returnedValueFromPython;
}
because we want to get the returned result from a Python we use the async
function in Javascript.
look closely at await eel.sendDataToJavaScript()();
you will see that we used ()()
and it is important (you can find out why here)
also, we used await
keyword because it's an async function.
And the Python part
# letsEel.py
import eel
eel.init('.//webPageFolder') # path of the webpage folder
@eel.expose
def printFromPython(dataFromJs):
print(dataFromJs)
@eel.expose
def sendDataToJavaScript():
return "this is some data that returned from python."
eel.start('index.html') # html file name
as you see it's a simple Python function. we still need to add @eel.expose
it because we want to call it from Javascript.
Now let's run it.
now if you hit Get From Python you will see this π
This is what we have done:
Part 3 Calling a Javascript function from Python
# letsEel.py
import eel
eel.init('.//webPageFolder') # path of the webpage folder
@eel.expose
def printFromPython(dataFromJs):
print(dataFromJs)
@eel.expose
def sendDataToJavaScript():
return "this is some data that returned from python."
eel.start('index.html', block=False) # html file name
while True:
eel.sleep(1.0) # it's important. else the page wont load. and this is insted of time.sleep(1.0)
userTyped = input("type something: ")
eel.alertThis(userTyped)()
As you see I changed this line a little bit: eel.start('index.html', block=False)
basically what block=False
does is (i think) allowing the codes after this line also execute. but why I didn't add the loop before this?!
Because that way the window would never open and we just stock in the loop.π
we should add some sleep time in the loop. even though we have an input that stops the code from running but if you don't add eel.sleep(1.0)
, The window will never load.
calling part(eel.alertThis(userTyped)()
) is the same as the last part but, here the Javascript function takes parameters so we should pass it on the first parenthesis()
.
and now the Javascript part
// webPageFolder/app.js
function SendDataToPython() { // this will call a python function directly from here
const input = document.getElementById("theFirstInput").value;
eel.printFromPython(input); // eel.thePythonFunctionToCall
}
async function getDataFromPython() { // this will also call another function from python and get returned result
let returnedValueFromPython = await eel.sendDataToJavaScript()();
document.getElementById("showDataFromPython").innerText = returnedValueFromPython;
}
eel.expose(alertThis);
function alertThis(someString) {
alert(someString);
}
Just like Python, that we added @eel.expose
here we add eel.expose(<the function name>)
because we want to call this function from the other side. In Javascript, we should write the function name too.
This function just gets a string and alerts it.
Now let's run this.
and we will get an alert.
Part 4 Getting returned value from a Javascript function called in Python
So we want to get the returned value of a Javascript function.
First, let's set up an input field on the HTML part.
<!-- webPageFolder/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<script type="text/javascript" src="eel.js"></script>
<title>Let's Eel</title>
</head>
<body>
<h1>Let's Eel</h1>
<h4>Send data to python </h4>
<div class="formJsToPy">
<input class="textInput" type="text" id="theFirstInput">
<input class="buttonInput" type="button" onclick="SendDataToPython()" value="Send" id="theBtn">
</div>
<hr>
<h4>Getting data from Python </h4>
<div class="formJsToPy">
<input class="buttonInput" type="button" onclick="getDataFromPython()" value="Get From Python" id="theBtnGet">
</div>
<p id="showDataFromPython"></p>
<hr>
<h4>Type here and see the python output terminal</h4>
<div class="formJsToPy">
<input class="textInput" type="text" id="theSecondInput">
</div>
<script src="app.js"></script>
</body>
</html>
And the Python part:
# letsEel.py
import eel
eel.init('.//webPageFolder') # path of the webpage folder
@eel.expose
def printFromPython(dataFromJs):
print(dataFromJs)
@eel.expose
def sendDataToJavaScript():
return "this is some data that returned from python."
eel.start('index.html', block=False) # html file name
while True:
eel.sleep(1.0) # it's important. else the page wont load. and this is insted of time.sleep(1.0)
# userTyped = input("type something: ")
# eel.alertThis(userTyped)()
dataFromJs = eel.getDataFromSecondInput()()
print(dataFromJs)
as you see I called a Javascript function(eel.getDataFromSecondInput()()
I explain why ()()
here)
let's define it:
// webPageFolder/app.js
function SendDataToPython() { // this will call a python function directly from here
const input = document.getElementById("theFirstInput").value;
eel.printFromPython(input); // eel.thePythonFunctionToCall
}
async function getDataFromPython() { // this will also call another function from python and get returned result
let returnedValueFromPython = await eel.sendDataToJavaScript()();
document.getElementById("showDataFromPython").innerText = returnedValueFromPython;
}
eel.expose(alertThis);
function alertThis(someString) {
alert(someString);
}
eel.expose(getDataFromSecondInput);
function getDataFromSecondInput() {
let data = document.getElementById("theSecondInput").value;
return data;
}
as I said before we should add eel.expose(getDataFromSecondInput)
before the function because we want to call it from Python.
what the function does is getting the value of the second input and return it.
What this part does is while you are typing on the input field every 1-second, will log to the Python terminal!
If you run the file and write something on the last input filed, you will get something like this:
App Icon
you just need to move the icon you want inside the webPageFolder
with the name favicon.ico
you can find some good icons on icons8.com or converting png to the icon by favicon.io.
On Edge browser
If you don't have a Chrome browser you can also use Edge on windows.
Just start like this eel.start(..., mode='edge')
and it will use the Edge to open the app.
You can find the whole code on this link.
Also there are some other examples here.
Let's get more specific here
NameError: name 'eel' is not defined
π really!? this means you didn't install the eel module. here
<function _call_return.<locals>.return_func at 0x0000021568EE0820>
it's because you didn't add the second parentheses after the Javascript function called by Python eel.javascriptfunction(param1, param2)()
[object Promise]
when you click on the Get button. it's because you missed await
keyword here let returnedValueFromPython = await eel.sendDataToJavaScript()()
function(callback = null) {
if(callback != null) {
eel._call_return_callbacks[call.call] = callback;
} else {
return new Promise(function(resolve) {
eel._call_return_callbacks[call.call] = resolve;
});
}
}
that weird thing is because you missed the second parentheses after the Python function called by Javascript ()()
Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
from the Javascript console: because you missed the async
keyword before the function name.
If the app doesn't work at all π, check these:
block=False
in the Python file (if you didn't use the callback functions! how to use callback functions?)@eel.expose
before the Python function that you want to call from JavascriptThis site canβt be reached
theeel.sleep(1.0)
should be before anything inside the while loop. (for part 3)
If you found any other errors just leave a comment about it. π