このページでは、スタンダード環境で Python 3 ランタイムを使用して、以前のバンドル サービスをインストールして使用する方法について説明します。アプリは、Python 3 用 App Engine サービス SDK を介してバンドル サービスにアクセスする必要があります。
始める前に
- Python 3 ランタイムで呼び出すことができる以前のバンドル サービス API のリストをご覧ください。
- Python 3 への移行プロジェクトを開始する前に、ランタイム移行の概要をご覧ください。また、以前のバンドル サービスを使用する場合は、移行に関する考慮事項もご覧ください。
App Engine サービス SDK のインストール
App Engine サービス SDK をインストールする手順は次のとおりです。
requirements.txt
ファイルに次の行を追加して、SDK をアプリに組み込みます。appengine-python-standard>=1.0.0
SDK は、GitHub の
appengine-python-standard
リポジトリと PyPI で入手できます。メインの Python スクリプトに次のコードを追加します。このコードは、API 呼び出しを有効にするために必要な変数を設定する WSGI ミドルウェアを作成します。
Flask
from flask import Flask from google.appengine.api import wrap_wsgi_app app = Flask(__name__) app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
Django
from DJANGO_PROJECT_NAME.wsgi import application from google.appengine.api import wrap_wsgi_app app = wrap_wsgi_app(application)
Pyramid
from pyramid.config import Configurator from google.appengine.api import wrap_wsgi_app config = Configurator() # make configuration settings app = config.make_wsgi_app() app = wrap_wsgi_app(app)
WSGI
import google.appengine.api def app(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) yield b'Hello world!\n' app = google.appengine.api.wrap_wsgi_app(app)
アプリをデプロイする前に、次の行を
app.yaml
に追加します。app_engine_apis: true
アプリをデプロイするには、
gcloud app deploy
コマンドを使用します。
移行に関する考慮事項
Python 3 ランタイムに移行し、アプリで以前のバンドル サービスを使用している場合は、次の考慮事項を把握しておいてください。
テスト
以前のバンドル サービスの機能をローカルの Python 3 アプリでテストするには、ローカル開発用サーバーを使用します。dev_appserver.py
コマンドを実行するときは、--runtime_python_path
引数を設定して、Python 3 インタープリタのパスを含める必要があります。次に例を示します。
python3 CLOUD_SDK_ROOT/bin/dev_appserver.py --runtime_python_path=/usr/bin/python3
[RUNTIME_ID]=[PYTHON_INTERPRETER_PATH]
ペアのカンマ区切りのリストに引数を設定することもできます。次に例を示します。
python3 CLOUD_SDK_ROOT/bin/dev_appserver.py --runtime_python_path="python27=/user/bin/python2.7,python3=/usr/bin/python3"
Pickle の互換性
Memcache、Cloud NDB、deferred などの共有サービスは、pickle モジュールを使用して Python オブジェクトをシリアル化して共有します。App Engine 環境で Python 2 と Python 3 の両方が使用されているケースは移行中によく見られるものですが、この場合、一方のバージョンの Python で記述された共有シリアル化オブジェクトをもう一方のバージョンで再構成できる必要があります。バージョン間の pickle 互換性の実装に関するガイダンスについては、ガイドをご覧ください。
デフォルトでは、Python 3 は Python 2 でサポートされていない pickle プロトコルを使用します。このため、Python 3 環境で記述された Python オブジェクトを Python 2 環境で再構築しようとすると、エラーが発生する可能性があります。この問題を回避するには、必要に応じて Python 3 アプリの app.yaml
ファイルで次の環境変数を設定します。
- Memcache を使用するアプリ(NDB を使用するアプリを含む)の場合は、
MEMCACHE_USE_CROSS_COMPATIBLE_PROTOCOL: 'True'
を設定します。 - NDB を使用して Datastore に接続するアプリの場合は、
NDB_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True'
を設定します。 - deferred を使用するアプリの場合、
DEFERRED_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True'
を設定します。
Python 2 では、string
オブジェクトは 8 ビットバイト値のシーケンスを保持します。Python 3 では、string
オブジェクトは Unicode 文字のシーケンスを保持します。デフォルトでは、Python 3 pickle は Python 3 string
を ASCII として解釈することで、Python 2 string
を Unicode に変換します。これにより、ASCII 文字範囲 0~127 の範囲外の値にエラーが発生する可能性があります。Memcache では、このデフォルト マッピングのオーバーライドがサポートされています。
from google.appengine.api import memcache
import six.moves.cPickle as pickle
def _unpickle_factory(file):
return pickle.Unpickler(file, encoding='latin1')
memcache.setup_client(memcache.Client(unpickler=_unpickle_factory))
latin1
エンコードは、Python 2 の string
の各バイトの 256 個の可能な値それぞれに対するマッピングを定義します。これにより、デコードエラーを防ぐことができます。ただし、Python 2 の string
に、latin1
の範囲外の実際の Unicode データ(ファイルから読み取られたデータなど)が含まれている場合、cPickle はデータを正しくマッピングしません。そのため、pickle するオブジェクトの場合は、string
オブジェクトではなく unicode
オブジェクトを使用して Unicode データを保持するように Python 2 コードを更新することが重要です。必要なアップデートについて詳しくは、互換性ガイドをご覧ください。
前述の Python 2 コードを更新して Python 3 と互換性のあるシリアル化を生成する方法は、有効期間の短いシリアル化(Memcache に保存されているものなど)に対処します。有効期間が長い Python 2 のシリアル化(移行の一環として Datastore に保存されたものなど)の更新または書き換えが必要になる場合があります。たとえば、google.appengine.ext.ndb.model.PickleProperty
を使用して記述されたシリアル化では、アップグレードが必要になる場合があります。
制限事項とあまり一般的でない問題の詳細については、互換性に関するガイドをご覧ください。
ウェブ フレームワーク
webapp2
は Python 3 ではバンドルまたはサポートされないため、すべてのアプリケーションは、WSGI 互換のフレームワーク(Flask など)を利用するように書き換えを行う必要があります。
おすすめの移行戦略は、Python 2.7 を維持したまま、最初に Python 2.7 アプリの webapp2
の使用を Flask(または Django、Pyramid、Bottle、web.py などの別のウェブ フレームワーク)に置き換えることです。その後、更新したアプリが安定したら、コードを Python 3 に移行し、Python 3 向けの App Engine を使用してデプロイとテストを行います。
webapp2
を使用する Python 2.7 アプリを Flask フレームワークの使用に変換する方法の例については、こちらの参考情報をご覧ください。
ハンドラの使用
Python 3 アプリには 1 つのスクリプトを関連付けることができます。このため、app.yaml
に複数の script
ハンドラがあり、URL を別のスクリプトにマッピングしている場合は、それらのスクリプトを 1 つのスクリプトに結合して URL ルーティングを処理する必要があります。
次の例は、各ランタイムの app.yaml
ファイルのハンドラの違いを示しています。
Python 2
runtime: python27 api_version: 1 threadsafe: true handlers: - url: / script: home.app - url: /index\.html script: home.app - url: /stylesheets static_dir: stylesheets - url: /(.*\.(gif|png|jpg))$ static_files: static/\1 upload: static/.*\.(gif|png|jpg)$ - url: /admin/.* script: admin.app login: admin - url: /.* script: not_found.app
Python 3
runtime: python312
app_engine_apis: true
handlers:
- url: /stylesheets
static_dir: stylesheets
- url: /(.*\.(gif|png|jpg))$
static_files: static/\1
upload: static/.*\.(gif|png|jpg)$
- url: /admin/.*
script: auto
login: admin
Python 3 アプリは、URL ルーティングを処理する必要があります(たとえば、Flask デコレータを使用して処理します)。
異なる URL パターンで複数の script
ハンドラを使用する場合や、ハンドラ内で他の属性を使用する場合は、各ハンドラに script: auto
を指定する必要があります。
app.yaml
ファイルで entrypoint
フィールドを指定すると、デフォルトの起動動作をオーバーライドすることもできます。
具体的なハンドラの使用方法については、Blobstore、Deferred、Mail の概要をご覧ください。
スレッドセーフ
アプリはスレッドセーフであると想定されます。API 呼び出しはリクエスト スレッドで実行する必要があります。アプリの起動時に以前のバンドル サービス API を使用すると、セキュリティ エラーが発生する可能性があります。
詳細については、Python 用の以前のバンドル サービスを使用する場合のセキュリティ エラーをご覧ください。
URL 取得の使用
Python 3 用の URL 取得を使用するには、URL 取得ライブラリを明示的に呼び出す必要があります。
Python 3 アプリで URL Fetch API を使用する場合、アプリが別の App Engine アプリにリクエストを送信すると、X-Appengine-Inbound-Appid
リクエスト ヘッダーが追加されます。これにより、受信側アプリは呼び出し元アプリの ID を検証できます。詳細については、送信リクエストの移行をご覧ください。
例(App Engine ndb
)
App Engine ndb
を使用して Datastore にアクセスするページ訪問を登録する基本的な Python 2 アプリを以下に示します。コンパニオンは Python 3 と同等のアプリです。webapp2
の使用は Flask に置き換えられており、Python 3 でバンドルされたサービスにアクセスするために、上記の必要な変更が実装されています。
Python 2(webapp2
)
Python 3(Flask)
どちらのアプリも、Python App Engine 移行コンテンツ(コードサンプル、動画、Codelab)のオープンソース リポジトリにあります。具体的には、それぞれ mod0
フォルダと mod1b
フォルダにあります。