Jupyter Notebook Kernel for Running ansible Tasks and Playbooks

Ansible Jupyter Kernel

Example Jupyter Usage

The Ansible Jupyter Kernel adds a kernel backend for Jupyter to interface directly with Ansible and construct plays and tasks and execute them on the fly.

Demo

Demo

Installation:

ansible-kernel is available to be installed from pypi but you can also install it locally. The setup package itself will register the kernel with Jupyter automatically.

From pypi

pip install ansible-kernel
python -m ansible_kernel.install

From a local checkout

pip install -e .
python -m ansible_kernel.install

For Anaconda/Miniconda

pip install ansible-kernel
python -m ansible_kernel.install --sys-prefix

Usage

Local install

    jupyter notebook
    # In the notebook interface, select Ansible from the 'New' menu

Container

docker run -p 8888:8888 benthomasson/ansible-jupyter-kernel

Then copy the URL from the output into your browser:
http://localhost:8888/?token=ABCD1234

Using the Cells

Normally Ansible brings together various components in different files and locations to launch a playbook and performs automation tasks. For this jupyter interface you need to provide this information in cells by denoting what the cell contains and then finally writing your tasks that will make use of them. There are Examples available to help you, in this section we'll go over the currently supported cell types.

In order to denote what the cell contains you should prefix it with a pound/hash symbol (#) and the type as listed here as the first line as shown in the examples below.

#inventory

The inventory that your tasks will use

#inventory
[all]
ahost ansible_connection=local
anotherhost examplevar=val

#play

This represents the opening block of a typical Ansible play

#play
name: Hello World
hosts: all
gather_facts: false

#task

This is the default cell type if no type is given for the first line

#task
debug:
#task
shell: cat /tmp/afile
register: output

#host_vars

This takes an argument that represents the hostname. Variables defined in this file will be available in the tasks for that host.

#host_vars Host1
hostname: host1

#group_vars

This takes an argument that represents the group name. Variables defined in this file will be available in the tasks for hosts in that group.

#group_vars BranchOfficeX
gateway: 192.168.1.254

#vars

This takes an argument that represents the filename for use in later cells

#vars example_vars
message: hello vars
#play
name: hello world
hosts: localhost
gather_facts: false
vars_files:
    - example_vars

#template

This takes an argument in order to create a templated file that can be used in later cells

#template hello.j2
{{ message }}
#task
template:
    src: hello.j2
    dest: /tmp/hello

#ansible.cfg

Provides overrides typically found in ansible.cfg

#ansible.cfg
[defaults]
host_key_checking=False

Examples

You can find various example notebooks in the repository

Using the development environment

It's possible to use whatever python development process you feel comfortable with. The repository itself includes mechanisms for using pipenv

pipenv install
...
pipenv shell

Author: ansible
Source Code:  https://github.com/ansible/ansible-jupyter-kernel
License: Apache-2.0 License

#jupyter #python 

What is GEEK

Buddha Community

Jupyter Notebook Kernel for Running ansible Tasks and Playbooks

Jupyter Notebook Kernel for Running ansible Tasks and Playbooks

Ansible Jupyter Kernel

Example Jupyter Usage

The Ansible Jupyter Kernel adds a kernel backend for Jupyter to interface directly with Ansible and construct plays and tasks and execute them on the fly.

Demo

Demo

Installation:

ansible-kernel is available to be installed from pypi but you can also install it locally. The setup package itself will register the kernel with Jupyter automatically.

From pypi

pip install ansible-kernel
python -m ansible_kernel.install

From a local checkout

pip install -e .
python -m ansible_kernel.install

For Anaconda/Miniconda

pip install ansible-kernel
python -m ansible_kernel.install --sys-prefix

Usage

Local install

    jupyter notebook
    # In the notebook interface, select Ansible from the 'New' menu

Container

docker run -p 8888:8888 benthomasson/ansible-jupyter-kernel

Then copy the URL from the output into your browser:
http://localhost:8888/?token=ABCD1234

Using the Cells

Normally Ansible brings together various components in different files and locations to launch a playbook and performs automation tasks. For this jupyter interface you need to provide this information in cells by denoting what the cell contains and then finally writing your tasks that will make use of them. There are Examples available to help you, in this section we'll go over the currently supported cell types.

In order to denote what the cell contains you should prefix it with a pound/hash symbol (#) and the type as listed here as the first line as shown in the examples below.

#inventory

The inventory that your tasks will use

#inventory
[all]
ahost ansible_connection=local
anotherhost examplevar=val

#play

This represents the opening block of a typical Ansible play

#play
name: Hello World
hosts: all
gather_facts: false

#task

This is the default cell type if no type is given for the first line

#task
debug:
#task
shell: cat /tmp/afile
register: output

#host_vars

This takes an argument that represents the hostname. Variables defined in this file will be available in the tasks for that host.

#host_vars Host1
hostname: host1

#group_vars

This takes an argument that represents the group name. Variables defined in this file will be available in the tasks for hosts in that group.

#group_vars BranchOfficeX
gateway: 192.168.1.254

#vars

This takes an argument that represents the filename for use in later cells

#vars example_vars
message: hello vars
#play
name: hello world
hosts: localhost
gather_facts: false
vars_files:
    - example_vars

#template

This takes an argument in order to create a templated file that can be used in later cells

#template hello.j2
{{ message }}
#task
template:
    src: hello.j2
    dest: /tmp/hello

#ansible.cfg

Provides overrides typically found in ansible.cfg

#ansible.cfg
[defaults]
host_key_checking=False

Examples

You can find various example notebooks in the repository

Using the development environment

It's possible to use whatever python development process you feel comfortable with. The repository itself includes mechanisms for using pipenv

pipenv install
...
pipenv shell

Author: ansible
Source Code:  https://github.com/ansible/ansible-jupyter-kernel
License: Apache-2.0 License

#jupyter #python 

Rodrigo Senra - Jupyter Notebooks

Nosso convidado de hoje é diretor técnico na Work & Co, PhD em Ciências da Computação, já contribuiu com inúmeros projetos open source em Python, ajudou a fundar a Associação Python Brasil e já foi premiado com o Prêmio Dorneles Tremea por contribuições para a comunidade Python Brasil.

#alexandre oliva #anaconda #apache zeppelin #associação python brasil #azure notebooks #beakerx #binder #c++ #closure #colaboratory #donald knuth #fernando pérez #fortran #graphql #guido van rossum #ipython #java #javascript #json #jupyter kenels #jupyter notebooks #jupyterhub #jupyterlab #latex #lisp #literate programming #lua #matlab #perl #cinerdia #prêmio dorneles tremea #python #r #rodrigo senra #scala #spark notebook #tcl #typescript #zope

Deploy Your First Jupyter Notebook to Docker

There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle. -Albert Einstein

In this article, we will talk about what Docker is, how it works and how to deploy a Jupyter notebook to a Docker Container.

#What is Docker?

 

docker-about.png

 

According to the Docker Website, Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly.

In other words, Docker is a platform that provides a container for you to run host, and run your applications in without bothering about things like platform dependence, it provides infrastructure called a container where your platforms can be held and run.

#What makes up Docker (In a Nutshell)

Here we will provide an overview of what docker up, if you want a comprehensive overview of how docker works, check this article out.

The Docker Architecture is divided into three(3) sections:

  • Docker Engine(dockerd)
  • docker-containerd (contained)
  • docker-runc (runc)

 

docker-2.png

Docker Engine(dockerd)

Docker engine comprises the docker daemon, an API interface, and Docker CLI. Docker daemon (dockerd) runs continuously as dockerd system service. It is responsible for building the docker images.

Docker-containerd

containerd is another system daemon service that is responsible for downloading the docker images and running them as a container. It exposes its API to receive instructions from the dockerd service

Docker-runc

runc is the container runtime responsible for creating the namespaces and cgroups required for a container. It then runs the container commands inside those namespaces. runc runtime is implemented as per the OCI specification.

How to Deploy a Colab Jupyter Notebook to a Docker Container

 

docker-0.png

 

 

In this part, we are going to work build a simple classifier model using the Iris Dataset, after that we will import the code from colab and finally we install and run deploy the script containing the model into a docker container.

#Building Model

In this section, we will build the classifier model using the sklearn's inbuilt Iris Dataset.

STEP 1: Create a new notebook in google colab.

colab-opening.png

STEP 2 Import the dependencies.

import matplotlib.pyplot as plt
from sklearn import metrics
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

STEP 3 Here we are going to load the iris dataset, split the data into the training set and test set, and build our classification model.

iris = load_iris()
X = iris.data
y = iris.target

Above we loaded the Iris dataset.

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2 , random_state=4)

Above we used the train_test_split function in sklearn to split the iris dataset into a training set and test set.

knn = KNeighborsClassifier(n_neighbors=10)
knn.fit(X,y)

Above we instantiated the KNeighbors Classifier model and tuned the n_neighbours hyperparameter to contain ten(10) neighbors.

Installing and deploying to Docker

This is the final chapter, here we are going to install the docker desktop application and write the scripts which will deploy our script to a docker container.

STEP 1 Firstly, you download the python script containing your trained model from colab.

colab-import-code.png

STEP 2 Now we are going to install and set up docker. You can install docker using this__link__ STEP 3 Now create a directory called iris-classifier where we are going to host our model and docker scripts.

Move the python file containing the iris classification model to the iris-classification folder just created.

In the same folder, create a text file called requirements, below are the contents it will contain.

sklearn==0.0
matplotlib==3.2.2

STEP 4 Here we will create the Dockerfile, go to your main directory and create a file called Dockerfile without any extension. A dockerfile is a script that is used to create a container image. Below are the items that will be contained in your Dockerfile.

FROM python:3.8

ADD requirements.txt /

RUN pip install -r /requirements.txt

ADD iris-classifier.py /

ENV PYTHONUNBUFFERED=1

CMD [ "python", "./iris-classifier.py" ]

Above we simply told docker what to do each time the container is run.

STEP 5 Here we are going to create our Docker Compose file, docker-compose files are simply configuration files that make it easy to maintain different Docker containers.

In your project directory, create a file called docker-compose.yml, below are the contents to be contained in the file.

version: "3"
services:
  iris-classifier-uplink:
    # if failure  or server restarts, container will restart
    restart: always 
    container_name: iris-classifier-uplink
    image: iris-classifier-uplink
    build: 
      # build classifier image from the Dockerfile in the current directory
      context: .

Now in your directory, iris-classifier you should have three(3) files.

#Running Docker Container

This is the final step, here we will run our docker container using the commands stated below.

docker compose build

docker compose up -d

This is the end, our Python model is now running in a docker container!

Useful Links

EndNote

Jupyter Notebooks are really good places for building models and you can also use them as back ends for applications, unfortunately, they don't run forever.

Docker helps you fix that by re-running your jupyter notebook when it fails and this makes it a tool worth knowing.

Source: https://hackernoon.com/deploy-your-first-jupyter-notebook-to-docker

#jupyter #notebook #docker 

坂本  健一

坂本 健一

1633583160

PythonでのCeleryを使用した非同期タスク

従来のWebアプリケーションは本質的に同期しています。 ユーザーはブラウザーに表示されるWebインターフェースを操作し、ブラウザーはそのユーザー操作に基づいてサーバーに要求を返し、サーバーはユーザーの新しい表示でそれらの要求に応答します。

今日、状況は変化しました。現代のWebサイトは、数十万の訪問者からの要求を処理する必要があります。これらの要求にデータベースまたはWebサービスとの対話が含まれる場合、応答時間が長くなり、何千もの訪問者が同じリソースにアクセスしている場合、Webサイトのパフォーマンスが大幅に低下する可能性があります。 ここで非同期Webが助けになります。

非同期性を選択したときに把握できる利点のいくつかを次に示します。

  • より多くのリクエストを処理する機能
  • I / Oバウンドメソッドの並列実行。
  • 応答性が向上しました。

範囲

このチュートリアルでは、新しい要求に応答するWebサーバーの機能を制限する長時間実行タスクを処理するWebアプリケーションを構築するときに発生する一般的な落とし穴の1つを克服する方法を説明します。

簡単な解決策は、これらの長時間実行タスクをバックグラウンドで非同期に、別のスレッドまたはプロセス内で実行し、Webサーバーを解放することです。

Redis、Flask、Celery、SocketIOなどのいくつかのコンポーネントを活用して、長時間実行されるタスクの実行をオフロードし、完了したら、クライアントにそのステータスを示すプッシュ通知を送信します。

このチュートリアルでは、コルーチンを使用してコードを同時に実行できるasyncioPythonの組み込みライブラリについては説明していません。

前提条件

要件が満たされると、次のコンポーネントが機能します。

Redis:は、オープンソースの高度なKey-Valueストアであり、高性能でスケーラブルなWebアプリケーションを構築するための適切なソリューションです。それを際立たせる3つの主な特徴があります:

Redisはデータベースを完全にメモリに保持し、永続性のためにのみディスクを使用します。

多くのKey-Valueデータストアと比較すると、Redisには比較的豊富なデータ型のセットがあります。

  • Redisは、任意の数のスレーブにデータを複製できます。

Redisのインストールは、このチュートリアルの範囲外です。ただし、Windowsマシンにインストールするには、このクイックガイドに従うことをお勧めします。

LinuxまたはmacOSを使用している場合は、以下のコマンドのいずれかを実行すると、Redisがセットアップされます。

Ubuntu / Debian:

$ sudo apt-get install redis-server

マックOS:

$ brew install redis
$ brew services start redis

注意: このチュートリアルでは、Redisバージョン3.0.504を使用しています

セロリ:Pythonの世界で最も人気のあるバックグラウンドジョブマネージャーの1人です。リアルタイム操作に重点を置いていますが、スケジューリングもサポートしています。RedisやRabbitMQなどのいくつかのメッセージブローカーと互換性があり、プロデューサーとコンシューマーの両方として機能できます。

requirements.txt ファイルにCeleryをインストールし ます。

注意: このチュートリアルでは、Celeryバージョン4.4.7を使用しています。

  • Socket.IO:リアルタイムWebアプリケーション用のJavaScriptライブラリです。これにより、Webクライアントとサーバー間のリアルタイムの双方向通信が可能になります。これには、ブラウザで実行されるクライアント側ライブラリとサーバー側ライブラリの2つの部分があります。 
  • Flask:Pythonで記述されたWebアプリケーションのマイクロフレームワーク。

食欲をそそる

このチュートリアルでは、スキャフォールディング手法を採用し、同期通信と非同期通信の違い、および非同期通信のバリエーションを理解するために、一連のさまざまなシナリオについて説明します。

すべてのシナリオはFlaskフレームワーク内で提示されます。ただし、それらのほとんどは他のPythonフレームワーク(Django、Pyramid)に簡単に移植できます。

このチュートリアルに興味をそそられ、すぐにコードに飛び込みたいと思う 場合は、この記事で使用されているコードについて、このGithubリポジトリにアクセス してください。

アプリケーションスケルトンの作成

私たちのアプリケーションは以下で構成されます:

  • app_sync.py 同期通信を紹介するプログラム 。
  • app_async1.py クライアントがポーリングメカニズムを使用してサーバー側プロセスのフィードバックを要求する可能性がある非同期サービス呼び出しを示すプログラム 。
  • app_async2.py クライアントへの自動フィードバックを伴う非同期サービス呼び出しを示すプログラム 。
  • app_async3.py クライアントへの自動フィードバックを伴う、スケジュール後の非同期サービス呼び出しを示すプログラム 。

セットアップに飛び込みましょう。もちろん 、システムにPython3をインストールする必要があり ます。私は必要なライブラリをインストールする仮想環境を使用します(そしてあなたも間違いなくそうするべきです):

$ python -m venv async-venv
$ source async-venv/bin/activate

名前の付いたファイルを作成し、 requirements.txt その中に次の行を追加します。

Flask==1.1.2
Flask-SocketIO==5.0.1
Celery==4.4.7
redis==3.5.3
gevent==21.1.2
gevent-websocket==0.10.1
flower==0.9.7

今それらをインストールします:

$ pip install -r requirements.txt

このチュートリアルを終了すると、フォルダー構造は次のようになります。

プロジェクト構造

それがクリアされたので、実際のコードを書き始めましょう。

まず、アプリケーションの構成パラメータを次のように定義します config.py

#config.py
#Application configuration File
################################

#Secret key that will be used by Flask for securely signing the session cookie
# and can be used for other security related needs
SECRET_KEY = 'SECRET_KEY'

#Map to REDIS Server Port
BROKER_URL = 'redis://localhost:6379'

#Minimum interval of wait time for our task
MIN_WAIT_TIME = 1
#Maximum interval of wait time for our task
MAX_WAIT_TIME = 20

注意:簡潔にするために、これらの構成パラメーターをにハードコーディングしましたが config.py、これらのパラメーターを別のファイル(たとえば.env)に保存することをお勧めします 。

次に、プロジェクトの初期化ファイルを次の場所に作成します init.py

#init.py
from flask import Flask

#Create a flask instance
app = Flask(__name__)
#Loads flask configurations from config.py
app.secret_key = app.config['SECRET_KEY']
app.config.from_object("config")

#Setup the Flask SocketIO integration (Required only for asynchronous scenarios)
from flask_socketio import SocketIO
socketio = SocketIO(app,logger=True,engineio_logger=True,message_queue=app.config['BROKER_URL'])

シナリオ1:同期通信の紹介

コーディングに入る前に、同期通信について簡単に説明します。

同期通信、発呼者がサービスを要求し、完全にサービスを待ち受けます。そのサービスの結果を受け取った場合にのみ、作業を続行します。タイムアウトを定義して、定義された期間内にサービスが終了しない場合、呼び出しは失敗したと見なされ、呼び出し元は続行します。 

同期通信がどのように機能するかを理解するために、専用のウェイターが割り当てられたと想像してください。彼はあなたの注文を受け取り、それをキッチンに届け、そこでシェフがあなたの料理を準備するのを待ちます。この間、ウェイターは何もしていません。

次の図は、同期サービス呼び出しを示しています。

同期通信

同期通信はシーケンシャルタスクに適していますが、同時タスクが多数ある場合、プログラムはスレッドを使い果たし、スレッドが使用可能になるまで新しいタスクを待機させる可能性があります。

それでは、コーディングに取り掛かりましょう。Flaskがレンダリングできるテンプレート(index.html)を作成し、その中に次のHTMLコードを含めます。

templates/index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Synchronicity versus Asynchronicity</title>
    <link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
    <script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
    <script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  </head>
  <body class="container">
    <div class="row">
        <h5>Click to start a post scheduled ansycnhronous task with automatic feedback.</h5>
    </div>
    <div class="card-panel">
      <form method='post' id="runTaskForm" action="/runPSATask">
          <div>
             <input id="duration" name="duration" placeholder="Enter duration in seconds. for example: 30" type="text">
             <label for="duration">Duration</label>
          </div>
          <button style="height:50px;width:600px" type="submit" id="runTask">Run A Post Scheduled Asynchronous Task With Automatic Feedback</button>
      </form>
    </div>
    <div class="row">
        <div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
    </div>
    <script>
      $(document).ready(function(){
        var namespace='/runPSATask';
        var url = 'http://' + document.domain + ':' + location.port + namespace;
        var socket = io.connect(url);
        socket.on('connect', function() {
                             socket.emit('join_room');
                            });

        socket.on('msg' , function(data) {
                            $("#Messages").prepend('<li>'+data.msg+'</li>');
                          });

        socket.on('status', function(data) {
                            ////alert('socket on status ='+ data.msg);
                            if (data.msg == 'End') {
                                $("#runTask").attr("disabled",false);
                            };
                          });
      });
    </script>
    <script>
      $("#runTask").click(function(e) {
         $("#runTask").attr("disabled",true);
         $("#Messages").empty();
         $.ajax({ type: "Post"
                , url: '/runPSATask'
                , data: $("#runTaskForm").serialize()
                , success: function(data) {
                    $("#Messages").empty();
                    $("#Messages").prepend('<li>The Task ' + data.taskid + ' has been submitted and will execute in ' + data.duration + ' seconds. </li>');
                  }
                });
         e.preventDefault();
         console.log('runPSATask complete');
      });
    </script>
  </body>
</html>

このテンプレートには次のものが含まれます。

  • runTaskルートを使用してサーバーにタスクを送信するボタン/runSyncTask
  • 結果はdividでに配置されMessagesます。

次に、app_sync.pyFlaskアプリケーションを含むというプログラムを作成し、このプログラム内に2つのルートを定義します。

  • "/"Webページをレンダリングします(index.html
  • "/runSyncTask"1〜20秒の乱数を生成し、反復ごとに1秒間スリープするループを実行する、長時間実行中のタスクをシミュレートします。
#app_sync.py
from flask import render_template, jsonify
from random import randint
from init import app
import tasks

#Render the predefined template index.html
@app.route("/",methods=['GET'])
def index():
    return render_template('index.html')

#Defining the route for running A Synchronous Task
@app.route("/runSyncTask",methods=['POST'])
def long_sync_task():
    print("Running","/runSyncTask")
    #Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
    n = randint(app.config['MIN_WAIT_TIME'],app.config['MAX_WAIT_TIME'])
    #Call the function long_sync_task included within tasks.py
    task = tasks.long_sync_task(n=n)
    #Return the random wait time generated
    return jsonify({ 'waittime': n })

if __name__ == "__main__":
    app.run(debug=True)

このチュートリアルで定義されているすべてのタスクのコアロジックは、プログラム内にありますtasks.py

#tasks.py
import time
from celery import Celery
from celery.utils.log import get_task_logger
from flask_socketio import SocketIO
import config

# Setup the logger (compatible with celery version 4)
logger = get_task_logger(__name__)

# Setup the celery client
celery = Celery(__name__)
# Load celery configurations from celeryconfig.py
celery.config_from_object("celeryconfig")

# Setup and connect the socket instance to Redis Server
socketio = SocketIO(message_queue=config.BROKER_URL)

###############################################################################
def long_sync_task(n):
    print(f"This task will take {n} seconds.")
    for i in range(n):
        print(f"i = {i}")
        time.sleep(1)
###############################################################################
@celery.task(name = 'tasks.long_async_task')
def long_async_task(n,session):
    print(f"The task of session {session}  will take {n} seconds.")
    for i in range(n):
        print(f"i = {i}")
        time.sleep(1)
###############################################################################
def send_message(event, namespace, room, message):
    print("Message = ", message)
    socketio.emit(event, {'msg': message}, namespace=namespace, room=room)

@celery.task(name = 'tasks.long_async_taskf')
def long_async_taskf(data):
    room      = data['sessionid']
    namespace = data['namespase']
    n         = data['waittime']

    #Send messages signaling the lifecycle of the task
    send_message('status', namespace, room, 'Begin')
    send_message('msg', namespace, room, 'Begin Task {}'.format(long_async_taskf.request.id))
    send_message('msg', namespace, room, 'This task will take {} seconds'.format(n))

    print(f"This task will take {n} seconds.")
    for i in range(n):
        msg = f"{i}"
        send_message('msg', namespace, room, msg )
        time.sleep(1)

    send_message('msg', namespace, room, 'End Task {}'.format(long_async_taskf.request.id))
    send_message('status', namespace, room, 'End')
###############################################################################
@celery.task(name = 'tasks.long_async_sch_task')
def long_async_sch_task(data):
    room      = data['sessionid']
    namespace = data['namespase']
    n         = data['waittime']

    send_message('status', namespace, room, 'Begin')
    send_message('msg'   , namespace, room, 'Begin Task {}'.format(long_async_sch_task.request.id))
    send_message('msg'   , namespace, room, 'This task will take {} seconds'.format(n))

    print(f"This task will take {n} seconds.")
    for i in range(n):
        msg = f"{i}"
        send_message('msg', namespace, room, msg )
        time.sleep(1)

    send_message('msg'   , namespace, room, 'End Task {}'.format(long_async_sch_task.request.id))
    send_message('status', namespace, room, 'End')
###############################################################################

このセクションでは、このlong_sync_task()関数を同期タスクとしてのみ使用します。

app_sync.pyプログラムを実行して、同期シナリオをテストしてみましょう。

$ python app_sync.py

http://localhost:5000Flaskインスタンスが実行されているリンクにアクセスすると、次の出力が表示されます。

Flaskアプリのホームページ

「同期タスクの実行」ボタンを押して、プロセスが完了するまで待ちます。

同期タスク実行後のホームページ

完了すると、トリガーされたタスクに割り当てられたランダムな時間を通知するメッセージが表示されます。

同時に、サーバーがタスクを実行すると、コンソールに1秒ごとに増分された数値が表示されます。

コンソールに表示されるタスク

シナリオ2:ポーリングメカニズムを使用した非同期サービス呼び出しの表示

このセクションでは、クライアントがポーリングメカニズムを使用してサーバー側プロセスのフィードバックを要求する可能性のある非同期サービス呼び出しを示します。

簡単に言うと、非同期とは、プログラムが特定のプロセスが完了するのを待たずに、関係なく続行することを意味します。

発信者が開始サービスコールが、やるES N結果をオト待ち時間。発信者は、結果を気にせずにすぐに作業を続行します。発信者が結果に関心がある場合は、後で説明するメカニズムがあります。

最も単純な非同期メッセージ交換パターンはファイアアンドフォーゲットと呼ばれ 、メッセージは送信されますがフィードバックは必要ありませんが、フィードバックが必要な場合、クライアントはポーリングメカニズムを介して結果を繰り返し要求することがあります 。

ポーリングは潜在的に高いネットワーク負荷を引き起こすため、お勧めしません。それでも、サービスプロバイダー(サーバー)がクライアントについて知る必要がないという利点があります。

次の図は、シナリオを示しています。

ポーリングメカニズムとの非同期通信非同期通信は、イベントに応答する必要のあるコード(たとえば、待機を伴う時間のかかるI / Oバウンド操作)に適しています。

非同期性を選択すると、システムは同時により多くの要求を処理できるようになり、スループットが向上します。

それでは、コーディングに移りましょう。構成ファイルを使用して、セロリの初期化パラメーターを定義しますceleryconfig.py

#celeryconfig.py
#Celery Configuration parameters
#Map to Redis server
broker_url = 'redis://localhost:6379/0'

#Backend used to store the tasks results
result_backend = 'redis://localhost:6379/0'

#A string identifying the default serialization to use Default json
task_serializer = 'json'
result_serializer = 'json'
accept_content = ['json']

#When set to false the local system timezone is used.
enable_utc = False

#To track the started state of a task, we should explicitly enable it
task_track_started = True

#Configure Celery to use a specific time zone.
#The timezone value can be any time zone supported by the pytz library
#timezone = 'Asia/Beirut'
#enable_utc = True

Flaskがレンダリングできるテンプレートを作成します(index1.html):

<!DOCTYPE html>
<html>
  <head>
    <title>Synchronicity versus Asynchronicity</title>
    <link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
    <script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  </head>
  <body class="container">
    <div class="row">
        <h4>Click to start an ansycnhronous task</h4>
    </div>
    <div class="card-panel">
      <form method='post' id="runTaskForm" action="/runAsyncTask">
          <button style="height:50px;width:400px" type="submit" id="runTask">Run An Asynchronous Task</button>
      </form>
      <form method='post' id="getTaskResultForm" action="/getAsyncTaskResult">
          <button style="height:50px;width:400px" type="submit" id="getTaskResult">Get Asynchronous Task Result</button>
      </form>
    </div>
    <div class="row">
        <div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
    </div>
    <script>
      $("#runTask").click(function(e) {
         $("#runTask").attr("disabled",true);
         $("*").css("cursor","wait");
         $("#Messages").empty();
         $.ajax({ type: "Post"
                , url: '/runAsyncTask'
                , data: $("#runTaskForm").serialize()
                , success: function(data) {
                    $("#runTask").attr("disabled",false);
                    $("*").css("cursor","");
                    $("#Messages").append('The task ' + data.taskid + ' will be executed in asynchronous manner for ' + data.waittime + ' seconds...');
                  }
                });
         e.preventDefault();
         console.log('runAsyncTask complete');
      });
      $("#getTaskResult").click(function(e) {
         var msg = $("#Messages").text();
         var taskid = msg.match("task(.*)will");
         //Get The Task ID from The Messages div and create a Target URL
         var vurl = '/getAsyncTaskResult?taskid=' + jQuery.trim(taskid[1]);
         $.ajax({ type: "Post"
                , url: vurl
                , data: $("#getTaskResultForm").serialize()
                , success: function(data) {
                    $("*").css("cursor","");
                    $("#Messages").append('<p> The Status of the task = ' + data.taskid + ' is ' + data.taskstatus + '</p>');
                  }
                });
         e.preventDefault();
         console.log('getAsyncTaskResult complete');
      });
    </script>
  </body>
</html>

次に、app_async1.pyFlaskアプリを含むプログラムを作成します。

#app_async1.py
from flask import render_template, jsonify, session,request
from random import randint
import uuid
import tasks
from init import app
from celery.result import AsyncResult

@app.route("/",methods=['GET'])
def index():
    # create a unique ID to assign for the asynchronous task
    if 'uid' not in session:
        sid = str(uuid.uuid4())
        session['uid'] = sid
        print("Session ID stored =", sid)
    return render_template('index1.html')

#Run an Asynchronous Task
@app.route("/runAsyncTask",methods=['POST'])
def long_async_task():
    print("Running", "/runAsyncTask")
    #Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
    n = randint(app.config['MIN_WAIT_TIME'],app.config['MAX_WAIT_TIME'])
    sid = str(session['uid'])
    task = tasks.long_async_task.delay(n=n,session=sid)
    #print('taskid',task.id,'sessionid',sid,'waittime',n )
    return jsonify({'taskid':task.id,'sessionid':sid,'waittime':n })

#Get The Result of The Asynchronous Task
@app.route('/getAsyncTaskResult', methods=['GET', 'POST'])
def result():
    task_id = request.args.get('taskid')
    # grab the AsyncResult
    result = AsyncResult(task_id)
    # print the task id
    print("Task ID = ", result.task_id)
    # print the Asynchronous result status
    print("Task Status = ", result.status)
    return jsonify({'taskid': result.task_id, 'taskstatus': result.status})

if __name__ == "__main__":
   app.run(debug=True)

このプログラムには、3つの主要なルートがあります。

  • "/":Webページをレンダリングします(index1.html)。
  • "/runAsyncTask":1〜20秒の乱数を生成する非同期タスクを呼び出してから、反復ごとに1秒間スリープするループを実行します。
  • "/getAsyncTaskResult":受信したタスクIDに基づいて、タスクの状態を収集します。

注意:このシナリオには、SocketIOコンポーネントは含まれていません。 

このシナリオをテストして、次の手順に従ってパスを進めましょう。

  • Redisサーバーを起動します。Windowsでは、Redisがインストールされているフォルダーを見つけて、をダブルクリックしredis-server.exeます。デフォルトのインストールまたはLinux / MacOSの場合は、RedisインスタンスがTCPポート6379で実行されていることを確認してください。
  • Celeryワーカーを起動します。Windowsでは、コマンドプロンプトを開き、プロジェクトフォルダーに移動して、次のコマンドを実行します。
$ async-venv\Scripts\celery.exe worker -A tasks --loglevel=DEBUG --concurrency=1 -P solo -f celery.logs

Linux / MacOSでは、非常によく似ています。

$ async-venv/bin/celery worker -A tasks --loglevel=DEBUG --concurrency=1 -P solo -f celery.logs

これasync-venvが仮想環境の名前であることに注意してください。別の名前を付けた場合は、必ず自分の名前に置き換えてください。セロリが始まると、次の出力が表示されます。セロリが定義したタスク

プログラムで定義されたタスクtasks.pyがCeleryに反映されていることを確認してください。

  • ターミナルウィンドウを開き、メインプログラムを起動します。
$ python app_async1.py​

次に、ブラウザを開いて、次のリンクにアクセスします。 

ポーリングメカニズムアプリとの非同期通信

[非同期タスクの実行]ボタンを押すと、新しいタスクがキューに入れられ、直接実行されます。「メッセージ」セクションに、タスクのIDとその実行時間を示すメッセージが表示されます。

[非同期タスク結果の取得]ボタンを(継続的に)押すと、その特定の時間におけるタスクの状態が収集されます。

セロリタスクの組み込み状態は次のとおりです。

  • PENDING:実行を待機しています。
  • STARTED:タスクが開始されました。
  • SUCCESS:タスクは正常に実行されました。
  • FAILURE:タスクの実行により例外が発生しました。
  • RETRY:タスクは再試行されています。
  • REVOKED:タスクが取り消されました。

ログファイルに含まれているセロリワーカーのログcelery.logsを確認すると、タスクのライフサイクルに気付くでしょう。

セロリログのタスクライフサイクルシナリオ3:自動フィードバックを使用した非同期サービス呼び出しの表示

以前のシナリオに基づいて、タスクの状態を収集するために複数のリクエストを開始することによる煩わしさを軽減するために、サーバーがタスクの状態に関してクライアントを継続的に更新できるようにするソケットテクノロジの組み込みを試みます。

実際、ソケットIOエンジンは、リアルタイムの双方向イベントベースの通信を可能にします。

これがもたらす主な利点は、ネットワークの負荷を軽減し、膨大な数のクライアントに情報を伝達するためにより効率的になることです。

次の図は、シナリオを示しています。

自動フィードバックによる非同期通信

さらに掘り下げる前に、実行する手順について簡単に説明します。

セロリからWebブラウザーにメッセージを送り返すことができるようにするために、以下を活用します。

  • Flask-SocketIOのメッセージキュー機能。これにより、Celeryワーカーがクライアントと通信できるようになります。
  • TのWebSocket接続を可能にするための使いやすいJavaScriptライブラリであるSocket.ioの彼の能力。

データ接続を効果的に管理するために、次の区分化戦略を採用します。

  • "/runAsyncTaskF"このシナリオに名前空間を割り当てます。(名前空間は、単一の共有接続を介してサーバーロジックを分離するために使用されます)。
  • W eは、各ユーザーセッションのための部屋を割り当てます。(部屋は名前空間のサブディビジョンまたはサブチャネルです)。

それでは、コーディングに移りましょう。

  • Flaskがレンダリングできるテンプレートを作成します(index2.html):
<!DOCTYPE html>
<html>
<head>
    <title>Synchronicity versus Asynchronicity</title>
    <link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
    <script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
    <script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body class="container">
    <div class="row">
        <h5>Click to start an ansycnhronous task with automatic feedback.</h5>
    </div>
    <div class="card-panel">
        <form method='post' id="runTaskForm" action="/runAsyncTask">
            <button style="height:50px;width:400px" type="submit" id="runTask">Run An Asynchronous Task With Automatic Feedback</button>
        </form>
    </div>
    <div class="row">
        <div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
    </div>
    <script>
        $(document).ready(function() {
            var namespace = '/runAsyncTaskF';
            var url = 'http://' + document.domain + ':' + location.port + namespace;
            var socket = io.connect(url);
            socket.on('connect', function() {
                ////alert('socket on connect');
                socket.emit('join_room');
            });
            socket.on('msg', function(data) {
                ////alert('socket on msg ='+ data.msg);
                $("#Messages").prepend('<li>' + data.msg + '</li>');
            });
            socket.on('status', function(data) {
                ////alert('socket on status ='+ data.msg);
                if (data.msg == 'End') {
                    $("#runTask").attr("disabled", false);
                };
            });
        });
    </script>
    <script>
        $("#runTask").click(function(e) {
            $("#runTask").attr("disabled", true);
            $("*").css("cursor", "wait");
            $("#Messages").empty();

            $.ajax({
                type: "Post",
                url: '/runAsyncTaskF',
                data: $("#runTaskForm").serialize(),
                success: function(data) {
                    $("*").css("cursor", "");
                    $("#Messages").empty();
                    $("#Messages").prepend('<li>The Task ' + data.taskid + ' has been submitted. </li>');
                }
            });
            e.preventDefault();
            console.log('runAsyncTaskF complete');
        });
    </script>
</body>
</html>

app_async2.pyFlaskアプリケーションを含むと呼ばれるプログラムを作成します。

#Gevent is a coroutine based concurrency library for Python
from gevent import monkey
#For dynamic modifications of a class or module
monkey.patch_all()
from flask import render_template, jsonify, session, request
from random import randint
import uuid
import tasks
from init import app, socketio
from flask_socketio import join_room

@app.route("/",methods=['GET'])
def index():
    # create a unique session ID and store it within the Flask session
    if 'uid' not in session:
        sid = str(uuid.uuid4())
        session['uid'] = sid
        print("Session ID stored =", sid)
    return render_template('index2.html')

#Run an Asynchronous Task With Automatic Feedback
@app.route("/runAsyncTaskF",methods=['POST'])
def long_async_taskf():
    print("Running", "/runAsyncTaskF")
    # Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
    n = randint(app.config['MIN_WAIT_TIME'], app.config['MAX_WAIT_TIME'])

    data = {}
    data['sessionid'] = str(session['uid'])
    data['waittime']  = n
    data['namespase'] = '/runAsyncTaskF'

    task = tasks.long_async_taskf.delay(data)
    return jsonify({ 'taskid':task.id
                    ,'sessionid':data['sessionid']
                    ,'waittime':data['waittime']
                    ,'namespace':data['namespase']
                    })

@socketio.on('connect', namespace='/runAsyncTaskF')
def socket_connect():
    #Display message upon connecting to the namespace
    print('Client Connected To NameSpace /runAsyncTaskF - ',request.sid)

@socketio.on('disconnect', namespace='/runAsyncTaskF')
def socket_connect():
    # Display message upon disconnecting from the namespace
    print('Client disconnected From NameSpace /runAsyncTaskF - ',request.sid)

@socketio.on('join_room', namespace='/runAsyncTaskF')
def on_room():
    room = str(session['uid'])
    # Display message upon joining a room specific to the session previously stored.
    print(f"Socket joining room {room}")
    join_room(room)

@socketio.on_error_default
def error_handler(e):
    # Display message on error.
    print(f"socket error: {e}, {str(request.event)}")

if __name__ == "__main__":
    # Run the application with socketio integration.
    socketio.run(app,debug=True)

このプログラムには、主に2つのルートがあります。

  • "/":Webページをレンダリングします(index2.html)。
  • "/runAsyncTaskF":以下を実行する非同期タスクを呼び出します。
    • 1〜20秒の乱数を生成します。
    • long_async_taskf() プログラム内のそれぞれのタスクを呼び出しますtasks.py

このシナリオを実行するには:

  • Redisサーバーを起動します。
  • セロリワーカーを起動します。
  • 走る app_async2.py

ブラウザを開き、次のリンクにアクセスしてボタンを押すと、次のような出力が徐々に表示されます。

自動フィードバックフラスコアプリとの非同期通信同時に、コンソールに次の出力が表示されます。

コンソール出力またcelery.logs、タスクのライフサイクルについてファイルをいつでも確認できます。

シナリオ4:自動フィードバックを使用してポートでスケジュールされた非同期サービスコールを表示する

このシナリオはシナリオ3に似ています。唯一の違いは、非同期タスクを直接実行する代わりに、このタスクがクライアントによって指定された特定の期間の後に実行されるようにスケジュールされることです。
 

コーディングに進みましょう。非同期タスクを実行する前に待機する時間を秒単位で表すindex3.html新しいフィールドを使用してテンプレートを作成し"Duration"ます。

<!DOCTYPE html>
<html>
<head>
    <title>Synchronicity versus Asynchronicity</title>
    <link rel="stylesheet" href="{{url_for('static',filename='css/materialize.min.css')}}">
    <script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
    <script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body class="container">
    <div class="row">
        <h5>Click to start a post scheduled ansycnhronous task with automatic feedback.</h5>
    </div>
    <div class="card-panel">
        <form method='post' id="runTaskForm" action="/runPSATask">
            <div>
                <input id="duration" name="duration" placeholder="Enter duration in seconds. for example: 30" type="text">
                <label for="duration">Duration</label>
            </div>
            <button style="height:50px;width:600px" type="submit" id="runTask">Run A Post Scheduled Asynchronous Task With Automatic Feedback</button>
        </form>
    </div>
    <div class="row">
        <div id="Messages" class="red-text" style="width:800px; height:400px; overflow-y:scroll;"></div>
    </div>
    <script>
        $(document).ready(function() {
            var namespace = '/runPSATask';
            var url = 'http://' + document.domain + ':' + location.port + namespace;
            var socket = io.connect(url);
            socket.on('connect', function() {
                socket.emit('join_room');
            });
            socket.on('msg', function(data) {
                $("#Messages").prepend('<li>' + data.msg + '</li>');
            });
            socket.on('status', function(data) {
                ////alert('socket on status ='+ data.msg);
                if (data.msg == 'End') {
                    $("#runTask").attr("disabled", false);
                };
            });
        });
    </script>
    <script>
        $("#runTask").click(function(e) {
            $("#runTask").attr("disabled", true);
            $("#Messages").empty();
            $.ajax({
                type: "Post",
                url: '/runPSATask',
                data: $("#runTaskForm").serialize(),
                success: function(data) {
                    $("#Messages").empty();
                    $("#Messages").prepend('<li>The Task ' + data.taskid + ' has been submitted and will execute in ' + data.duration + ' seconds. </li>');
                }
            });
            e.preventDefault();
            console.log('runPSATask complete');
        });
    </script>
</body>
</html>

次に、app_async3.pyこのシナリオのFlaskアプリは次のとおりです。

#app_async3.py
from gevent import monkey
monkey.patch_all()

from flask import render_template, jsonify, session, request
from random import randint
import uuid
import tasks
from init import app, socketio
from flask_socketio import join_room

@app.route("/",methods=['GET'])
def index():
    # create a unique session ID
    if 'uid' not in session:
        sid = str(uuid.uuid4())
        session['uid'] = sid
        print("Session ID stored =", sid)
    return render_template('index3.html')

#Run a Post Scheduled Asynchronous Task With Automatic Feedback
@app.route("/runPSATask",methods=['POST'])
def long_async_sch_task():
        print("Running", "/runPSATask")
        # Generate a random number between MIN_WAIT_TIME and MAX_WAIT_TIME
        n = randint(app.config['MIN_WAIT_TIME'], app.config['MAX_WAIT_TIME'])
        data = {}
        data['sessionid'] = str(session['uid'])
        data['waittime']  = n
        data['namespase'] = '/runPSATask'
        data['duration']  = int(request.form['duration'])
        #Countdown represents the duration to wait in seconds before running the task
        task = tasks.long_async_sch_task.apply_async(args=[data],countdown=data['duration'])
        return jsonify({ 'taskid':task.id
                        ,'sessionid':data['sessionid']
                        ,'waittime': data['waittime']
                        ,'namespace':data['namespase']
                        ,'duration':data['duration']
                        })


@socketio.on('connect', namespace='/runPSATask')
def socket_connect():
    print('Client Connected To NameSpace /runPSATask - ',request.sid)

@socketio.on('disconnect', namespace='/runPSATask')
def socket_connect():
    print('Client disconnected From NameSpace /runPSATask - ',request.sid)

@socketio.on('join_room', namespace='/runPSATask')
def on_room():
    room = str(session['uid'])
    print(f"Socket joining room {room}")
    join_room(room)

@socketio.on_error_default
def error_handler(e):
    print(f"socket error: {e}, {str(request.event)}")

if __name__ == "__main__":
    socketio.run(app,debug=True)

今回long_async_sch_task()からタスクメソッドを使用していることに注意してくださいtasks.py

app_async3.py以前と同じように実行し、ブラウザを開きます。

シナリオ4アプリ期間(つまり10)を入力し、ボタンを押して、スケジュール後の非同期タスクを作成します。作成されると、タスクの詳細を示すメッセージが[メッセージ]ボックスに表示されます。

期間フィールドで指定した時間待つ必要があります。タスクが実行されていることがわかります。

実行中のスケジュールされたタスクを投稿するまた、celery.logsログファイルに含まれているセロリワーカーのログを復元すると、タスクのライフサイクルに気付くでしょう。

シナリオ4のログファイル付録:セロリの監視に花を使用する

セロリタスクをより適切に監視するために、セロリ クラスターを監視および管理するためのWebベースのツールであるFlowerをインストールできます。

注意:フラワーライブラリはの一部でしたrequirements.txt。 

花を使用してセロリのタスクを表示するには、次の手順に従ってください。

  • 以前と同じようにRedisサーバーを起動します。
  • 以前と同じようにCeleryワーカーを起動します。
  • Windowsでは、コマンドを使用してflowerを開始します。
$ async-venv\Scripts\flower.exe worker -A tasks --port=5555

Linux / MacOSの場合:

$ async-venv/bin/flower worker -A tasks --port=5555

コンソールに次の情報が表示されます。

花が始まりましたアプリに戻ってタスクを実行し、ブラウザを開いてhttp://localhost:5555[タスク]タブに移動します。

花のホームページ

タスクが完了すると、フラワーダッシュボードに次のように表示されます。

フラワーダッシュボードのセロリで達成されたタスク結論

この記事が、Celeryの助けを借りて同期および非同期リクエストの概念的な基礎を得るのに役立つことを願っています。同期要求は遅くなる可能性があり、非同期要求は迅速に実行されますが、あらゆるシナリオに適切な方法を認識することが重要です。時には、彼らは一緒に働くことさえあります。

リンク: https://www.thepythoncode.com/article/async-tasks-with-celery-redis-and-flask-in-python

#python 
 

 

Poetry Kernel: Python Jupyter Kernel Using Poetry for Reproducible Notebooks

Poetry Kernel

Use per-directory Poetry environments to run Jupyter kernels. No need to install a Jupyter kernel per Python virtual environment!

The idea behind this project is to allow you to capture the exact state of your environment. This means you can email your work to your peers, and they'll have exactly the same set of packages that you do! Reproducibility!

Why not virtual environments (venvs)?

Virtual environments were (and are) an important advancement to Python's package management story, but they have a few shortcomings:

  • They are not great for reproducibility. Usually, you'll create a new virtual environment using a requirements.txt which includes all the direct dependencies (numpy, pandas, etc.), but not transient dependencies (pandas depends on pytz for timezone support, for example). And usually, even the direct dependencies are specified only as minimum (or semver) ranges (e.g., numpy>=1.21) which can make it hard or impossible to accurately recreate the venv later.
  • With Jupyter, they usually require that the kernels be installed globally. This means you'll need need to have a separate kernelspec for every venv you want to use with Jupyter.

Poetry uses venvs transparently under the hood by constructing them from the pyproject.toml and poetry.lock files. The poetry.lock file records the exact state of dependencies (and transient dependencies) and can be used to more accurately reproduce the environment.

Additionally, Poetry Kernel means you only have to install one kernelspec. It then uses the pyproject.toml file from the directory of the notebook (or any parent directory) to choose which environment to run the notebook in.

Shameless plug

The reason we created this package was to make sure that the code environments created for running student code on Pathbird exactly match your development environment. Interested in developing interactive, engaging, inquiry-based lessons for your students? Check out Pathbird for more information!

Usage

# NOTE: Do **NOT** install this package in your Poetry project, it should be
# installed at the system or user level.
pip3 install --user poetry-kernel
  • Initialize a Poetry project (only required if you do not have an existing Poetry project ready to use):
poetry init -n
  • IMPORTANT: Add ipykernel to your project's dependencies:
# In the directory of your Poetry project
poetry add ipykernel
  • Start a "Poetry" Jupyter kernel and see it in action! 
Jupyter launcher screenshot

Troubleshooting

Kernel isn't starting ("No Kernel" message)

Pro-tip: Check the output of the terminal window where you launched Jupyter. It will usually explain why the kernel is failing to start.

  • Make sure that you are launching a notebook in a directory/folder that contains a Poetry project (pyproject.toml and poetry.lock files). You can turn a directory into a Poetry project by running:
poetry init -n
  • Make sure that you've installed ipykernel into your project:
poetry add ipykernel

Make sure the Poetry project is installed! This is especially important for projects that you have downloaded from others (warning: installing a Poetry project could run arbitrary code on your computer, make sure you trust your download first!):

Still can't figure it out? Open an issue!

A package I added won't import properly

If you added the package after starting the kernel, you might need to restart the kernel for it to see the new package.

 

Download Details: 
Author: pathbird
Source Code: https://github.com/pathbird/poetry-kernel 
License: MIT
 

#python #poetry #jupyter #kernel