Skip to content
This repository was archived by the owner on Jun 22, 2025. It is now read-only.

Commit 24cee9a

Browse files
authored
Fix parsing minified code with PEG (#363) (#365)
Update JS function name parsing Use a custom PyParsing grammar to extract function names from JavaScript names rather than a basic and somewhat flawed regex pattern.
1 parent 2e671b6 commit 24cee9a

File tree

13 files changed

+187
-9
lines changed

13 files changed

+187
-9
lines changed

README-developers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Create a dev virtual environment. Your process for doing this may vary, but migh
1313

1414
```bash
1515
python3 -m venv venv
16-
./venv/bin/activate
16+
source venv/bin/activate
1717
```
1818

1919
We support Python 3.6+ so developers should ideally run their tests against the latest minor version of each major version we support from there. Tox is configured to run tests against each major version we support. In order to run tox fully, you will need to install multiple versions of Python. See the pinned minor versions in `.python-version`.

eel/__init__.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import re as rgx
1111
import os
1212
import eel.browsers as brw
13+
import pyparsing as pp
1314
import random as rnd
1415
import sys
1516
import pkg_resources as pkg
@@ -83,6 +84,22 @@ def decorator(function):
8384
return function
8485

8586

87+
# PyParsing grammar for parsing exposed functions in JavaScript code
88+
# Examples: `eel.expose(w, "func_name")`, `eel.expose(func_name)`, `eel.expose((function (e){}), "func_name")`
89+
EXPOSED_JS_FUNCTIONS = pp.ZeroOrMore(
90+
pp.Suppress(
91+
pp.SkipTo(pp.Literal('eel.expose('))
92+
+ pp.Literal('eel.expose(')
93+
+ pp.Optional(
94+
pp.Or([pp.nestedExpr(), pp.Word(pp.printables, excludeChars=',')]) + pp.Literal(',')
95+
)
96+
)
97+
+ pp.Suppress(pp.Regex(r'["\']?'))
98+
+ pp.Word(pp.printables, excludeChars='"\')')
99+
+ pp.Suppress(pp.Regex(r'["\']?\s*\)')),
100+
)
101+
102+
86103
def init(path, allowed_extensions=['.js', '.html', '.txt', '.htm',
87104
'.xhtml', '.vue'], js_result_timeout=10000):
88105
global root_path, _js_functions, _js_result_timeout
@@ -98,12 +115,8 @@ def init(path, allowed_extensions=['.js', '.html', '.txt', '.htm',
98115
with open(os.path.join(root, name), encoding='utf-8') as file:
99116
contents = file.read()
100117
expose_calls = set()
101-
finder = rgx.findall(r'eel\.expose\(([^\)]+)\)', contents)
102-
for expose_call in finder:
103-
# If name specified in 2nd argument, strip quotes and store as function name
104-
if ',' in expose_call:
105-
expose_call = rgx.sub(r'["\']', '', expose_call.split(',')[1])
106-
expose_call = expose_call.strip()
118+
matches = EXPOSED_JS_FUNCTIONS.parseString(contents).asList()
119+
for expose_call in matches:
107120
# Verify that function name is valid
108121
msg = "eel.expose() call contains '(' or '='"
109122
assert rgx.findall(r'[\(=]', expose_call) == [], msg

examples/07 - CreateReactApp/eel_CRA.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ def start_eel(develop):
5555
say_hello_py('Python World!')
5656
eel.say_hello_js('Python World!') # Call a JavaScript function (must be after `eel.init()`)
5757

58+
eel.show_log('https://github.com/samuelhwilliams/Eel/issues/363 (show_log)')
59+
5860
eel_kwargs = dict(
5961
host='localhost',
6062
port=8080,

examples/07 - CreateReactApp/src/App.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ function sayHelloJS( x: any ) {
1313
// WARN: must use window.eel to keep parse-able eel.expose{...}
1414
window.eel.expose( sayHelloJS, 'say_hello_js' )
1515

16+
// Test anonymous function when minimized. See https://github.com/samuelhwilliams/Eel/issues/363
17+
function show_log(msg:string) {
18+
console.log(msg)
19+
}
20+
window.eel.expose(show_log, 'show_log')
21+
1622
// Test calling sayHelloJS, then call the corresponding Python function
1723
sayHelloJS( 'Javascript World!' )
1824
eel.say_hello_py( 'Javascript World!' )

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ bottle-websocket==0.2.9
33
gevent==1.3.6
44
gevent-websocket==0.10.1
55
greenlet==0.4.15
6+
pyparsing==2.4.7
67
whichcraft==0.4.1

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
package_data={
1515
'eel': ['eel.js'],
1616
},
17-
install_requires=['bottle', 'bottle-websocket', 'future', 'whichcraft'],
17+
install_requires=['bottle', 'bottle-websocket', 'future', 'pyparsing', 'whichcraft'],
1818
extras_require={
1919
"jinja2": ['jinja2>=2.10']
2020
},

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def driver():
2121
# Firefox doesn't currently supported pulling JavaScript console logs, which we currently scan to affirm that
2222
# JS/Python can communicate in some places. So for now, we can't really use firefox/geckodriver during testing.
2323
# This may be added in the future: https://github.com/mozilla/geckodriver/issues/284
24-
24+
2525
# elif TEST_BROWSER == "firefox":
2626
# options = webdriver.FirefoxOptions()
2727
# options.headless = True

tests/data/init_test/App.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React, { Component } from 'react';
2+
import logo from './logo.svg';
3+
import './App.css';
4+
5+
// Point Eel web socket to the instance
6+
export const eel = window.eel
7+
eel.set_host( 'ws://localhost:8080' )
8+
9+
// Expose the `sayHelloJS` function to Python as `say_hello_js`
10+
function sayHelloJS( x: any ) {
11+
console.log( 'Hello from ' + x )
12+
}
13+
// WARN: must use window.eel to keep parse-able eel.expose{...}
14+
window.eel.expose( sayHelloJS, 'say_hello_js' )
15+
16+
// Test anonymous function when minimized. See https://github.com/samuelhwilliams/Eel/issues/363
17+
function show_log(msg:string) {
18+
console.log(msg)
19+
}
20+
window.eel.expose(show_log, 'show_log')
21+
22+
// Test calling sayHelloJS, then call the corresponding Python function
23+
sayHelloJS( 'Javascript World!' )
24+
eel.say_hello_py( 'Javascript World!' )
25+
26+
// Set the default path. Would be a text input, but this is a basic example after all
27+
const defPath = '~'
28+
29+
interface IAppState {
30+
message: string
31+
path: string
32+
}
33+
34+
export class App extends Component<{}, {}> {
35+
public state: IAppState = {
36+
message: `Click button to choose a random file from the user's system`,
37+
path: defPath,
38+
}
39+
40+
public pickFile = () => {
41+
eel.pick_file(defPath)(( message: string ) => this.setState( { message } ) )
42+
}
43+
44+
public render() {
45+
eel.expand_user(defPath)(( path: string ) => this.setState( { path } ) )
46+
return (
47+
<div className="App">
48+
<header className="App-header">
49+
<img src={logo} className="App-logo" alt="logo" />
50+
<p>{this.state.message}</p>
51+
<button className='App-button' onClick={this.pickFile}>Pick Random File From `{this.state.path}`</button>
52+
</header>
53+
</div>
54+
);
55+
}
56+
}
57+
58+
export default App;

tests/data/init_test/hello.html

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{% extends 'base.html' %}
2+
{% block title %}Hello, World!{% endblock %}
3+
{% block head_scripts %}
4+
eel.expose(say_hello_js); // Expose this function to Python
5+
function say_hello_js(x) {
6+
console.log("Hello from " + x);
7+
}
8+
9+
eel.expose(js_random);
10+
function js_random() {
11+
return Math.random();
12+
}
13+
14+
function print_num(n) {
15+
console.log('Got this from Python: ' + n);
16+
}
17+
18+
eel.py_random()(print_num);
19+
20+
say_hello_js("Javascript World!");
21+
eel.say_hello_py("Javascript World!"); // Call a Python function
22+
{% endblock %}
23+
{% block content %}
24+
Hello, World!
25+
<br />
26+
<a href="page2.html">Page 2</a>
27+
{% endblock %}

tests/data/init_test/minified.js

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)