python-eel / Eel

A little Python library for making simple Electron-like HTML/JS GUI apps
MIT License
6.44k stars 587 forks source link

Javascript function not running in python file (Eel React App) #449

Open antrikshmisri opened 3 years ago

antrikshmisri commented 3 years ago

Describe the problem I am trying to run eel with react using Eel-React-Template. I have a javascript function exposed in index.html but when I try to run the function from a python file I get the following error:

Traceback (most recent call last):
  File "main.py", line 13, in <module>
    eel.getFiles(files)
AttributeError: module 'eel' has no attribute 'getFiles'

Code snippet(s) My directory structure is:-

│ .gitignore │ main.py │ rest of the files ├───public │------index.html │------rest of the files ├───src │-----App.js │-----eel.js │-----index.js │-----*rest of the files***

This is my App.js:-

import "./App.css";
import React , {Component , useState} from "react"
import { eel } from "./eel.js";

function App() {
  let [value , setValue] = useState('')
  eel.set_host("ws://localhost:8888");
  eel.getpara("argument")(res => setValue(value = res)) //Python function from javascript
  return (
    <div className="App">
        <div className="Main">
          <h1>Hello</h1>
          <p>{value}</p>
          <p className="para"></p>
        </div>
    </div>
  );
}
export default App;

This is my main.py:-

import eel
import sys

@eel.expose
def getpara(arg):
    return f"You passed {arg}"

files = ['file1' , 'file2' , 'file3']

try:
    eel.getFiles(files) # Javascript function from python
except AttributeError:
    raise AttributeError('Eel function error')

if __name__ == '__main__':
    if sys.argv[1] == '--develop':
        eel.init('client')
        eel.start({
            'port': 3000,
        }, options={
            'port': 8888,
            'host': 'localhost',
        } , suppress_error = True)
    else:
        eel.init('build')
        eel.start('index.html')

This is my index.html:-

<html>
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <script src="http://localhost:8888/eel.js"></script>
    <script>
      eel.expose(getFiles);
      function getFiles(files)
      {
        files.map((file) => {
          document.querySelector(".para").innerHTML += String(file);
        });
      }
    </script>
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>

  </body>
</html>

Desktop (please complete the following information):

Smartphone (please complete the following information):

antrikshmisri commented 3 years ago

@ChrisKnott @samuelhwilliams Can you guys help me with this?

amantiwari1 commented 3 years ago

Found Solution!! @antrikshmisri
from

      eel.expose(getFiles);
      function getFiles(files)
      {
        files.map((file) => {
          document.querySelector(".para").innerHTML += String(file);
        });
      }

to this

      function getFiles(files)
      {
        files.map((file) => {
          document.querySelector(".para").innerHTML += String(file);
        });
      }
       window.eel.expose( getFiles, 'getFiles' )

Let me Know It Works or not

antrikshmisri commented 3 years ago

@amantiwari1 Thanks for the solution but unfortunately it is not working for me partly because of the way the eel is running. I think the issue is that python is trying to access a javascript function that has not been initialized yet. As python functions can be called by javascript (because running python functions from javascript gives eel enough time to expose the functions) , a workaround would be:-

First declare and expose the javascript function

function getFiles(files)
      {
        files.map((file) => {
          document.querySelector(".para").innerHTML += String(file);
        });
      }
       window.eel.expose( getFiles, 'getFiles' )

Then declare and expose a python function that calls the javascript function

@eel.expose
def run_javascript():
    eel.getFiles([args])

Then call the exposed python function from javascript:

eel.run_javascript()

This doesn't give any errors but doesn't run the function either , i am stuck at this part and is bugging me alot 😞

amantiwari1 commented 3 years ago

@antrikshmisri, try this

def GetFiles():
    eel.getFiles([args])

@eel.expose
def run_javascript():
    GetFiles()

Let me Know It Works or not

kinga112 commented 5 months ago

If anyone still has this issue I found a solution that works for me. This is my eel init: eel.init('client/src/api', allowed_extensions=['.ts']). My Typescript function is directly under this path: client/src/api, I also needed to allow .ts extension, add js, jsx or tsx if needed. In my ts file my function looks like this:

eel.expose(getEmailsPortal) function getEmailsPortal(){ getEmails() }

I create a portal function for python to run another TS function because I dont think eel allows export, and async doesnt always run how I expect, but you can mess around with that.