Let's eel (Vol.1 Basics)

by erfan

Posted on: 2021-04-13


Let's eel (Vol.1 Basics)

15 minutes read (just reading not understanding)

Topics:

 

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:

  1. Calling a Python function from Javascript
  2. Getting returned value from a Python function called by Javascript
  3. Calling a Javascript function from Python
  4. 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.

webPageFolder
webPag...
letsEel.py
letsEe...
index.html
index....
styles.css
styles.css
app.js
app.js
Viewer does not support full SVG 1.1
# 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:

  1. link the stylesheet <link rel="stylesheet" href="styles.css">
  2. add the Javascript at the end <script src="app.js"></script>
  3. and the most important thing is this tag <script type="text/javascript" src="eel.js"></script> even if you don't have the file named eel.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:

  1. <input class="textInput" type="text" id="theFirstInput">
  2. <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
}
  1. we select the input field's value with document.getElementById("theFirstInput").value
  2. 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
  1. before any Python function that we want to call from js, we should add @eel.expose. (if you don't it will not work)
  2. 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.

Output after hitting Send.

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.

Before hitting 

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.

Third part run

 

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:

Forth part run

 

 

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

 

Some possible errors

 

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:

  1. block=False in the Python file (if you didn't use the callback functions! how to use callback functions?)
  2. @eel.expose before the Python function that you want to call from Javascript
  3. This site can’t be reached the eel.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. πŸ˜‰

 

Check this out

eelslap.com πŸ˜‚πŸ˜‚πŸ˜‚


Tags:

Leave a Comment: