2018年7月にGoogle Cloud FunctionsでPython 3.7がサポートされました(2018/11現在β版)。Flaskの関数を実装するだけでWeb APIが1個作れるので、特に小規模なサービスや小さな処理(Pub/Subからキックされる処理など)を書くにはもってこいのサービスだと言えます。
Cloud Functionsの引数のメソッド補完ができなくて不便
ところで、Cloud Functionsの処理を書く際に、引数のメソッド補完が効かないのが個人的に気になりました。
具体的には、下記のような関数を書いた場合にrequest
のメソッド補完が効きません。
def hello_world(request):
request_json = request.get_json()
if request_json and 'message' in request_json:
name = request_json['message']
else:
name = 'World'
return 'Hello, {}!'.format(name)
このrequest
の型はflask.Request
なのですが、Cloud Functionsでは関数だけをポンと書く形になるので、補完が効かないのは当然といえば当然です。
解決策
この問題の解決策ですが、doccommentで型を明示した上でPyCharmを使うと無事補完が効くようになります。
def hello_world(request):
"""HTTP Cloud Function.
Args:
request (flask.Request): The request object.
<http://flask.pocoo.org/docs/1.0/api/#flask.Request>
Returns:
The response text, or any set of values that can be turned into a
Response object using `make_response`
<http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
"""
request_json = request.get_json()
if request_json and 'name' in request_json:
name = request_json['name']
else:
name = 'World'
return 'Hello {}!'.format(escape(name))
もしくは下記のように指定することもできます。
def hello_world(request):
"""
:type request: flask.Request
"""
request_json = request.get_json()
if request_json and 'message' in request_json:
name = request_json['message']
else:
name = 'World'
return 'Hello, {}!'.format(name)
当初Emacs+Jediで同じことをやろうとしていたのですが、挫折してPyCharmに頼ることにしました…。
PubSub用functionの場合
Pub/Subからキックされる関数についても次のように書くことで補完が効くはずです。ただし、私の手元にはgoogle.cloud.functions.Context
がpip install
されていないので補完が効きません。まだbetaだから公開されてないってことなんですかね…?
def hello_pubsub(data, context):
"""Background Cloud Function to be triggered by Cloud Storage.
This generic function logs relevant data when a file is changed.
Args:
data (dict): The Cloud Functions event payload.
context (google.cloud.functions.Context): Metadata of triggering event.
Returns:
None; the output is written to Stackdriver Logging
"""
import base64
if 'data' in data:
name = base64.b64decode(data['data']).decode('utf-8')
else:
name = 'World'
context
print('Hello {}!'.format(name))