GitHubじゃ!Pythonじゃ!

GitHubからPython関係の優良リポジトリを探したかったのじゃー、でも英語は出来ないから日本語で読むのじゃー、英語社会世知辛いのじゃー

ChrisKnott

Eel – 簡単なElectron-like HTML / JS GUIアプリケーションを作成するためのPythonライブラリ

投稿日:2018年4月4日 更新日:

簡単なElectron-like HTML / JS GUIアプリケーションを作成するためのPythonライブラリ

Eel

EelはPythonの機能とライブラリに完全にアクセスできる、シンプルなエレクトロンのようなオフラインHTML / JS GUIアプリケーションを作成するための小さなPythonライブラリです。

ローカルWebサーバをホストし、Pythonで関数に注釈を付けることで、Javascriptから呼び出すことができます。逆もまた同様です。

これは短くて簡単なGUIアプリケーションを書くことから手間を払うように設計されています。 PythonやWeb開発に精通している方は、 この例にジャンプし 、指定されたフォルダからランダムなファイル名を選んでください(ブラウザからは不可能なもの)。

 

イントロダクション

PythonでGUIアプリケーションを作成するにはいくつかのオプションがありますが、HTML / JS(例えばjQueryUIやBootstrapを使用するために)を使用する場合は、一般的にクライアントから通信する定型コードをたくさん記述する必要があります)側からサーバー(Python)側に移動します。

Electron(私の知る限り)に最も近いPythonはcefpythonです。 私が望んでいたのはちょっと重い。

EelはElectronやcefpythonほど本格的ではありません。Atomのような完全なアプリケーションを作成するのには適していませんが、チーム内で使用する小さなユーティリティスクリプトとGUIを同等にするには非常に適しています。

何らかの理由で、クラス最高数の数学や数学ライブラリの多くがPython(Tensorflow、Numpy、Scipyなど)にありますが、最高の視覚ライブラリの多くはJavaScript(D3、THREE.jsなど)にあります。 Eelはこれらを組み合わせて開発を支援する簡単なユーティリティアプリにすることを願っています。

インストール

pypiからpipを用いてインストールできます。

pip install eel

使用法

構造

Eelアプリケーションは、さまざまなWebテクノロジファイル(.html、.js、.css)とさまざまなPythonスクリプトで構成されるバックエンドで構成されるフロントエンドに分割されます。

すべてのフロントエンドファイルは単一のディレクトリに置く必要があります(必要に応じて、これをさらに内部のフォルダに分割することもできます)。

my_python_script.py     <-- Python scripts
other_python_module.py
static_web_folder/      <-- Web folder
  main_page.html
  css/
    style.css
  img/
    logo.png

アプリの起動

すべてのフロントエンドファイルをwebというディレクトリに置いたとします。開始ページmain.htmlを含めて、このようにアプリケーションが起動します。

import eel
eel.init('web')
eel.start('main.html')

これにより、デフォルト設定( http:// localhost:8000 )でWebサーバーが起動し、 http:// localhost:8000 / main.htmlのブラウザが開きます。

ChromeまたはChromiumがインストールされている場合、デフォルトでは、OSのデフォルトブラウザが設定されているかどうかに関係なく、App Mode( – --app cmdlineフラグ)で--appます(この動作を無効にすることができます)。

アプリのオプション

options={}引数を渡すことによって、 eel.start()追加のオプションを渡すことができます。

オプションには、アプリのモード( ‘chrome’、 ‘chrome-app’、None)、アプリが実行されるポート、アプリのホスト名、Chrome / Chromiumコマンドラインフラグの追加などがあります。

デフォルトは次のように設定されています。

_default_options = {
    'mode': 'chrome-app',
    'host': 'localhost',
    'port': 8000,
    'chromeFlags': ""
}
クロム/クロムフラグ

Chrome / Chromiumのコマンドラインフラグを追加するには、 optionsディクショナリのchromeFlags属性にリストを渡してからこれをeel.start()渡しoptions

web_app_options = {
	'mode': "chrome-app", #or "chrome"
	'port': 8080,
	'chromeFlags': ["--start-fullscreen", "--browser-startup-dialog"]
}

eel.start('main.html', options=web_app_options)

関数を公開する

frontendフォルダのファイルに加えて、Javascriptライブラリが/eel.jsで提供され/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

複雑なオブジェクトを引数として渡すときは、内部的にJSONに変換され、websocket(潜在的に情報を失うプロセス)を送信することに注意してください。

Eello, 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

eel.init('web')                     # Give folder containing web files

@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つの方法をサポートしています。

コールバック

公開された関数を呼び出すと、後でコールバック関数をすぐに渡すことができます。 このコールバックは、関数がもう一方の側で実行を終了したときに、戻り値と非同期的に自動的に呼び出されます。

たとえば、次の関数が定義され、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 immeadiately returns the value
print('Got this from Javascript:', n)

ブラウザウィンドウが起動した後eel.start()呼び出した後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();

非同期Python

ウナギはボトルとジーヴェントに建てられています。 Pythonの組み込みthread.sleep()を使用すると、インタプリタ全体がグローバルにブロックされます。 代わりに、Geventが提供するメソッドを使用する必要があります。 簡単にするために、最も一般的に必要な2つのメソッドsleep()spawn()はEelから直接提供されます。

例えば:

import eel
eel.init('web')

def my_other_thread():
    while True:
        print("I'm a thread")
        eel.sleep(1.0)                  # Must use eel.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)                      # Must use eel.sleep()

次に、3つの「スレッド」(グリーンレット)を実行します。

  1. Webフォルダを提供するためのEelの内部スレッド
  2. my_other_threadメソッドは、 “I’m a thread”を繰り返し印刷します。
  3. 最終的なwhileループに詰め込まれるメインのPythonスレッドは、 「私はメインループです」と繰り返し印刷します。

配布可能なバイナリの作成

Pythonインタプリタがインストールされていないコンピュータで実行できるプログラムにアプリケーションをパッケージ化する場合は、 pyinstallerを使用する必要があります。

  1. pyinstaller pip install pyinstaller
  2. あなたのアプリケーションのフォルダで、 python -m eel [your_main_script] [your_web_folder]実行します(例えば、 python -m eel hello.py web実行するかもしれません)
  3. これにより、新しいフォルダdist/
  4. pyinstallerが間違って含んでいる追加のモジュールがないか、このフォルダの内容を確認してください
  5. --exclude module_nameフラグを使用してこれらを除外します。 たとえば、 python -m eel file_access.py web --exclude win32com --exclude numpy --exclude cryptography実行するとします。
  6. あなたのアプリケーションが正常に動作していることがうれしいときは、– --onefile --noconsoleフラグを追加して単一の実行可能ファイルを作成してください

詳細については、pyinstallerマニュアルを参照してください。







-ChrisKnott

執筆者: