かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Azure Functions v2 で Python がサポートされました(プレビュー)

プレビューだけど、Azure Functions で Python のサポートが追加されました。

英語ですが、ドキュメントもちゃんとありますね!

docs.microsoft.com

ドキュメントにも記載がありますが現在サポートされている Python のバージョンは 3.6.x みたいです。3.7 ではないみたいですね。私のローカルには Python 3.6.2 が入ってたのですが折角なので最新の 3.6.7 を以下のサイトからダウンロードしてインストールしました。

www.python.org

C:\Users\ユーザー名\AppData\Local\Programs\Python\Python36C:\Users\ユーザー名\AppData\Local\Programs\Python\Python36\Scripts\ にパスを通して以下のコマンドで確認してみます。(インストール時にパス通すチェックボックスがあるみたいなのですが、さくっとインストールしたので見逃してました)

>>python --version
Python 3.6.7

私の環境は Windows なのですが、Azure Functions で Python を動かすときは Linux がベースの OS みたいなので、実際に開発するときは Linux でしたほうが幸せな気がしてます。

Visual Studio Code に Azure Functions と Python の拡張機能を入れて準備完了です。func init コマンドをうつか、Visual Studio Code でフォルダを開いて左側のアイコンの並びで Azure アイコンをクリックすると FUNCTIONS というものがあるので、Create new project をクリックして GUI でも可能です。

f:id:okazuki:20181211111855p:plain

どちらの手順でも言語を選ぶようになるので Python を選びましょう。

プロジェクトが出来たら、続けて func new か Visual Studio Code で Create Function をクリックして関数を作ります。

f:id:okazuki:20181211113704p:plain

Http Trigger で、Echo という名前でさくっと作ってみました。Authorization level は Function (関数単位でアクセスするためのキーが出来る)を選びました。

そうすると、__init__.py というファイル名で以下のようなコードが生成されます。

import logging

import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        return func.HttpResponse(f"Hello {name}!")
    else:
        return func.HttpResponse(
             "Please pass a name on the query string or in the request body",
             status_code=400
        )

Python にも Java でいう Annotation や C# でいう Attribute が無さそうなので、node と同じように function.json に関数のトリガーや入力や出力を定義する形みたいです。以下のような function.json が生成されていました。

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

おもむろに func startF5 を押して実行してみます。Echo 関数のエンドポイントが表示されるので適当なツールなりブラウザで叩いてみます。今回は curl 使いました。実行するとちゃんと動いてますね!

> curl http://localhost:7071/api/Echo?name=okazuki


StatusCode        : 200
StatusDescription : OK
Content           : Hello okazuki!

カスタマイズとか

init.py の main 関数が呼び出されるのがデフォルトなのですが、これは function.json でカスタマイズ出来ます。

scriptFileentoryPoint で指定する感じです。ドキュメントのこの部分に書いてあります。

docs.microsoft.com

共通ロジックとか

プロジェクトの下に SharedCode とかいうフォルダ(名前は任意)を作って、その中に logic.py とかいうファイルを作って以下のような関数を定義しました。

def generateGreetingMessage(name: str) -> str:
    return "Hello " + name

そして、__init__.py を以下のように書き換えてみます。

import logging

from ..ShreadCode.logic import generateGreetingMessage
import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        return func.HttpResponse(generateGreetingMessage(name))
    else:
        return func.HttpResponse(
             "Please pass a name on the query string or in the request body",
             status_code=400
        )

実行同じように実行するとちゃんと動きました!

> curl http://localhost:7071/api/Echo?name=okazuki

StatusCode        : 200
StatusDescription : OK
Content           : Hello okazuki

Azure Functions の拡張機能を使う

例えば Azure Storage の QueueTrigger なんかを使おうとしたときには拡張機能を入れます。その時は以下のようなコマンドをうちます。

func extensions install --package Microsoft.Azure.WebJobs.Extensions.Storage --version 3.0.2

詳細はここらへんに書いてあります。

docs.microsoft.com

試しに QueueTrigger で関数を作ります。func new か VS Code の Create Function で。

適当に入力を進めていくと以下のような関数が作られます。

import logging

import azure.functions as func


def main(msg: func.QueueMessage) -> None:
    logging.info('Python queue trigger function processed a queue item: %s',
                 msg.get_body().decode('utf-8'))

function.json は以下のような感じ。

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "name": "msg",
      "type": "queueTrigger",
      "direction": "in",
      "queueName": "python-queue-items",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

とりあえず、Queue に投げ込まれたメッセージを出力するだけみたいですね。 local.settings.json を開くと AzureWebJobsStorage という項目があるので、そこの値を UseDevelopmentStorage=true にして、エミュレーターにいくようにしておきます。 ローカルで実行して、Azure Storage Explorer あたりで適当に Queue にメッセージを投げ込んでみました。

f:id:okazuki:20181211123056p:plain

ばっちり!

[12/11/2018 3:31:59 AM] Trigger Details: MessageId: c9f676c5-91d9-4a50-81a0-c4ca5d4531dc, DequeueCount: 1, InsertionTime: 12/11/2018 3:28:40 AM +00:00
[12/11/2018 3:31:59 AM] Python queue trigger function processed a queue item: {
  "message": "Hello world"
}
[12/11/2018 3:31:59 AM] Executed 'Functions.QueueFunc' (Succeeded, Id=0ac16f9a-6594-49ca-ae9b-d0d11528b416)

デプロイ

そのままデプロイしてみました。VS Code だと Deploy to Function App を押すだけ。 私は zip をパッケージから実行する方法でデプロイしてみました。

docs.microsoft.com

ポータルでもばっちり関数が見えてます。

f:id:okazuki:20181211130715p:plain

ポータルから関数の URL を取得するとクリックすると関数の URL が認証キー付きでゲットできるので叩いてみましょう。

f:id:okazuki:20181211131324p:plain

curl コマンドで叩いてみました。

> curl "https://pyfunckaota.azurewebsites.net/api/Echo?code=キーの値&name=MicrosoftAzure"


StatusCode        : 200
StatusDescription : OK
Content           : Hello MicrosoftAzure

いい感じですね。

まとめ

Java と Python 早く GA しないかなぁ。