Eel は、Python の機能とライブラリに完全にアクセスできる、シンプルな Electron のようなオフライン HTML/JS GUI アプリを作成するための小さな Python ライブラリです。
Eel はローカル Web サーバーをホストし、Python で関数に注釈を付けることができるため、JavaScript から関数を呼び出すことができ、またその逆も可能です。
Eel は、短くてシンプルな GUI アプリケーションを作成する手間を省くように設計されています。 Python と Web 開発に精通している場合は、指定されたフォルダーからランダムなファイル名を選択する (ブラウザーでは不可能な) この例に進んでください。
Python で GUI アプリを作成するにはいくつかのオプションがありますが、HTML/JS を使用したい場合 (たとえば、jQueryUI または Bootstrap を使用するため)、通常、クライアントから通信するための多くの定型コード (JavaScript) を作成する必要があります。 ) 側からサーバー (Python) 側へ。
(私の知る限り) Electron に最も近い Python は cefpython です。欲しかったものにしては少し重いです。
Eel は Electron や cefpython ほど本格的ではありません。Atom のような本格的なアプリケーションの作成にはおそらく適していません。しかし、チーム内で使用する小さなユーティリティ スクリプトに相当する GUI を作成するには非常に適しています。
何らかの理由で、クラス最高の数値処理および数学ライブラリの多くは Python (Tensorflow、Numpy、Scipy など) で作られていますが、最高の視覚化ライブラリの多くは Javascript (D3、THREE.js など) で作られています。 Eel によって、これらを簡単に組み合わせて、開発を支援するシンプルなユーティリティ アプリが作成できるようになれば幸いです。
よろしければ、Discord で Eel のユーザーやメンテナーに参加してください。
pip
を使用して pypi からインストールします。
pip install eel
現在 Jinja2 を使用している HTML テンプレートのサポートを含めるには:
pip install eel[jinja2]
Eel アプリケーションは、さまざまな Web テクノロジー ファイル (.html、.js、.css) で構成されるフロントエンドと、さまざまな Python スクリプトで構成されるバックエンドに分割されます。
すべてのフロントエンド ファイルは 1 つのディレクトリに配置する必要があります (必要に応じて、このディレクトリ内でさらにフォルダに分割できます)。
my_python_script.py <-- Python scripts
other_python_module.py
static_web_folder/ <-- Web folder
main_page.html
css/
style.css
img/
logo.png
スタート ページmain.html
を含むすべてのフロントエンド ファイルをweb
というディレクトリに配置すると、アプリは次のように起動されます。
import eel
eel . init ( 'web' )
eel . start ( 'main.html' )
これにより、デフォルト設定 (http://localhost:8000) で Web サーバーが起動し、ブラウザで http://localhost:8000/main.html が開きます。
Chrome または Chromium がインストールされている場合、OS のデフォルトのブラウザーの設定に関係なく、デフォルトでアプリ モード ( --app
cmdline フラグを使用) で開きます (この動作をオーバーライドすることは可能です)。
追加のオプションをキーワード引数としてeel.start()
に渡すことができます。
オプションには、アプリのモード (例: 「chrome」)、アプリが実行されるポート、アプリのホスト名、追加のコマンド ライン フラグが含まれます。
Eel v0.12.0 では、 start()
で次のオプションを使用できます。
'chrome'
、 'electron'
、 'edge'
、 'msie'
、 'custom'
)。ウィンドウを開かない場合は、 None
またはFalse
指定することもできます。デフォルト: 'chrome'
'localhost'
)0
使用します。デフォルト: 8000
。start()
の呼び出しが呼び出しスレッドをブロックするかどうかを示すブール値。デフォルト: True
my_templates
。デフォルト: None
eel.start('main.html', mode='chrome-app', port=8080, cmdline_args=['--start-fullscreen', '--browser-startup-dialog'])
。デフォルト: []
None
None
{'size': (200, 100), 'position': (300, 50)}
の形式の辞書である必要があります。デフォルト: {}None
app
Bottle インスタンスでない場合は、カスタム アプリ インスタンスでeel.register_eel_routes(app)
を呼び出す必要があります。shutdown_delay
秒間待機し、WebSocket 接続が存在するかどうかを確認します。そうでない場合は、Eel は閉じます。ユーザーがブラウザを閉じてプログラムを終了したい場合。デフォルトでは、 shutdown_layの値は1.0
秒です。フロントエンド フォルダー内のファイルに加えて、JavaScript ライブラリが/eel.js
で提供されます。これをどのページにも含める必要があります。
< script type =" text/javascript " src =" /eel.js " > </ script >
このライブラリを含めると、Python 側との通信に使用できるeel
オブジェクトが作成されます。
このように@eel.expose
で装飾されている Python コード内の関数...
@ eel . expose
def my_python_function ( a , b ):
print ( a , b , a + b )
...このように、JavaScript 側のeel
オブジェクトのメソッドとして表示されます...
console . log ( "Calling Python..." ) ;
eel . my_python_function ( 1 , 2 ) ; // This calls the Python function that was decorated
同様に、このように公開される Javascript 関数も...
eel . expose ( my_javascript_function ) ;
function my_javascript_function ( a , b , c , d ) {
if ( a < b ) {
console . log ( c * d ) ;
}
}
このようにPython側から呼び出すことができます...
print ( 'Calling Javascript...' )
eel . my_javascript_function ( 1 , 2 , 3 , 4 ) # This calls the Javascript function
公開された名前は、2 番目の引数を渡すことによってオーバーライドすることもできます。アプリがビルド中に JavaScript を縮小する場合、Python 側で関数を確実に解決できるようにするためにこれが必要になる場合があります。
eel . expose ( someFunction , "my_javascript_function" ) ;
複雑なオブジェクトを引数として渡すときは、内部でオブジェクトが JSON に変換され、WebSocket (情報が失われる可能性があるプロセス) に送信されることに留意してください。
完全な例は、examples/01 - hello_world で参照してください。
これをまとめてHello, World!たとえば、短い HTML ページweb/hello.html
があります。
<!DOCTYPE html >
< html >
< head >
< title > Hello, World! </ title >
<!-- Include eel.js - note this file doesn't exist in the 'web' directory -->
< script type =" text/javascript " src =" /eel.js " > </ script >
< script type =" text/javascript " >
eel . expose ( say_hello_js ) ; // Expose this function to Python
function say_hello_js ( x ) {
console . log ( "Hello from " + x ) ;
}
say_hello_js ( "Javascript World!" ) ;
eel . say_hello_py ( "Javascript World!" ) ; // Call a Python function
</ script >
</ head >
< body >
Hello, World!
</ body >
</ html >
および短い Python スクリプトhello.py
:
import eel
# Set web files folder and optionally specify which file types to check for eel.expose()
# *Default allowed_extensions are: ['.js', '.html', '.txt', '.htm', '.xhtml']
eel . init ( 'web' , allowed_extensions = [ '.js' , '.html' ])
@ eel . expose # Expose this function to Javascript
def say_hello_py ( x ):
print ( 'Hello from %s' % x )
say_hello_py ( 'Python World!' )
eel . say_hello_js ( 'Python World!' ) # Call a Javascript function
eel . start ( 'hello.html' ) # Start (this blocks and enters loop)
Python スクリプト ( python hello.py
) を実行すると、ブラウザ ウィンドウが開き、 hello.html
が表示されます。
Hello from Python World!
Hello from Javascript World!
...ターミナル内、そして...
Hello from Javascript World!
Hello from Python World!
...ブラウザ コンソール内 (F12 を押して開きます)。
Python コードでは、ブラウザ ウィンドウが開始される前に Javascript 関数が呼び出されていることがわかります。このような初期の呼び出しはキューに入れられ、WebSocket が確立されると送信されます。
コードは単一のアプリケーションを構成していると考えたいのですが、Python インタープリターとブラウザ ウィンドウは別のプロセスで実行されます。これにより、特に一方の側からもう一方の側に常に値を明示的に送信する必要がある場合、両者の間での通信が少し面倒になる可能性があります。
Eel は、アプリの反対側から戻り値を取得する 2 つの方法をサポートしており、コードを簡潔に保つのに役立ちます。
Python 側で永久にハングするのを防ぐために、JavaScript 側から値を取得しようとするときにタイムアウトが設定されています。デフォルトは 10000 ミリ秒 (10 秒) です。これは、 _js_result_timeout
パラメータをeel.init
に設定することで変更できます。 JavaScript 側には対応するタイムアウトがありません。
公開された関数を呼び出すと、その後すぐにコールバック関数を渡すことができます。このコールバックは、関数が反対側で実行を終了したときに、戻り値と非同期で自動的に呼び出されます。
たとえば、次の関数が JavaScript で定義され公開されているとします。
eel . expose ( js_random ) ;
function js_random ( ) {
return Math . random ( ) ;
}
次に、Python では次のように JavaScript 側からランダムな値を取得できます。
def print_num ( n ):
print ( 'Got this from Javascript:' , n )
# Call Javascript function, and pass explicit callback function
eel . js_random ()( print_num )
# Do the same with an inline lambda as callback
eel . js_random ()( lambda n : print ( 'Got this from Javascript:' , n ))
(逆もまったく同じように機能します)。
ほとんどの場合、相手側への呼び出しは、ウィジェットの状態や入力フィールドの内容などのデータを迅速に取得することです。このような場合、全体をコールバックに分割するよりも、同期的に数ミリ秒待ってからコードを続行する方が便利です。
戻り値を同期的に取得するには、2 番目のかっこセットに何も渡さないだけです。したがって、Python では次のように書きます。
n = eel . js_random ()() # This immediately returns the value
print ( 'Got this from Javascript:' , n )
同期リターンを実行できるのは、ブラウザ ウィンドウが起動した後 ( eel.start()
を呼び出した後) のみです。そうしないと、明らかに呼び出しがハングします。
JavaScript では、 async
関数内からawait
を使用する場合を除き、コールバックを待機している間ブロックすることはできません。したがって、JavaScript 側の同等のコードは次のようになります。
async function run ( ) {
// Inside a function marked 'async' we can use the 'await' keyword.
let n = await eel . py_random ( ) ( ) ; // Must prefix call with 'await', otherwise it's the same syntax
console . log ( "Got this from Python: " + n ) ;
}
run ( ) ;
Eel は、JavaScript に似た非同期イベント ループを提供する Bottle と Gevent に基づいて構築されています。 Python の標準ライブラリの多くは、実行スレッドが 1 つであることを暗黙的に前提としています。これに対処するために、Gevent はtime
などの標準モジュールの多くに「モンキー パッチ」を適用できます。このモンキーパッチ適用は、 。モンキーパッチが必要な場合は、 import eel
呼び出すと自動的に行われます。import eel
前にimport gevent.monkey
し、 gevent.monkey.patch_all()
を呼び出す必要があります。モンキー パッチはデバッガなどに干渉する可能性があるため、必要な場合を除き避けてください。
ほとんどの場合、 time.sleep()
の使用を避け、代わりにgevent
が提供するバージョンを使用すれば問題ありません。便宜上、最も一般的に必要な 2 つの gevent メソッド、 sleep()
とspawn()
が Eel から直接提供されています (インポートtime
やgevent
も節約するため)。
この例では...
import eel
eel . init ( 'web' )
def my_other_thread ():
while True :
print ( "I'm a thread" )
eel . sleep ( 1.0 ) # Use eel.sleep(), not time.sleep()
eel . spawn ( my_other_thread )
eel . start ( 'main.html' , block = False ) # Don't block on this call
while True :
print ( "I'm a main loop" )
eel . sleep ( 1.0 ) # Use eel.sleep(), not time.sleep()
...その後、3 つの「スレッド」(グリーンレット) が実行されることになります。
my_other_thread
メソッド。 「私はスレッドです」を繰り返し出力します。while
ループでスタックし、 「私はメイン ループです」と繰り返し出力します。 Python インタープリターがインストールされていないコンピューター上で実行できるプログラムにアプリをパッケージ化する場合は、 PyInstaller を使用する必要があります。
pip install PyInstaller
python -m eel [your_main_script] [your_web_folder]
を実行します (たとえば、 python -m eel hello.py web
実行します)。dist/
が作成されます。--exclude module_name
フラグを使用してモジュールを除外するなど、有効な PyInstaller フラグを渡すことができます。たとえば、 python -m eel file_access.py web --exclude win32com --exclude numpy --exclude cryptography
を実行できます。--onefile --noconsole
フラグを追加して、単一の実行可能ファイルをビルドします。その他のオプションについては、PyInstaller のドキュメントを参照してください。
Windows 10 ユーザーの場合、Microsoft Edge ( eel.start(.., mode='edge')
) がデフォルトでインストールされます。これは、優先ブラウザがインストールされていない場合に便利なフォールバックです。例を参照してください。