Mengakses layanan paket lama untuk Python 3

Halaman ini menjelaskan cara menginstal dan menggunakan layanan paket lama dengan runtime Python 3 untuk lingkungan standar. Aplikasi Anda harus mengakses layanan yang dipaketkan melalui SDK layanan App Engine untuk Python 3.

Sebelum memulai

Menginstal SDK layanan App Engine

Untuk menginstal SDK layanan App Engine, ikuti langkah-langkah berikut:

  1. Sertakan SDK tersebut dengan aplikasi Anda dengan menambahkan baris berikut ke file requirements.txt:

    appengine-python-standard>=1.0.0
    

    Anda dapat menemukan SDK ini di GitHub di bagian repo appengine-python-standard, dan di PyPI.

  2. Tambahkan kode berikut di skrip Python utama Anda. Kode ini membuat middleware WSGI yang menetapkan variabel yang diperlukan untuk mengaktifkan panggilan API Anda.

    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)
    
  3. Tambahkan baris berikut ke file app.yaml Anda sebelum men-deploy aplikasi:

    app_engine_apis: true
    
  4. Untuk men-deploy aplikasi Anda, gunakan perintah gcloud app deploy.

Pertimbangan migrasi

Anda harus mengetahui pertimbangan berikut jika bermigrasi ke runtime Python 3 dan aplikasi Anda menggunakan layanan paket lama.

Pengujian

Untuk menguji fungsi layanan lama yang dipaketkan secara lokal di aplikasi Python 3 Anda, gunakan server pengembangan lokal. Saat menjalankan perintah dev_appserver.py, Anda harus menetapkan argumen --runtime_python_path untuk menyertakan jalur ke penafsir Python 3. Contoh:

   python3 CLOUD_SDK_ROOT/bin/dev_appserver.py --runtime_python_path=/usr/bin/python3

Anda juga dapat menyetel argumen ke daftar pasangan [RUNTIME_ID]=[PYTHON_INTERPRETER_PATH] yang dipisahkan koma. Contoh:

   python3 CLOUD_SDK_ROOT/bin/dev_appserver.py --runtime_python_path="python27=/user/bin/python2.7,python3=/usr/bin/python3"

Kompatibilitas Pickle

Layanan bersama termasuk Memcache, Cloud NDB, dan yang ditangguhkan menggunakan modul itemle untuk melakukan serialisasi dan berbagi objek Python. Jika lingkungan App Engine Anda menggunakan python 2 dan Python 3, yang umum selama migrasi, Anda harus memastikan bahwa objek serial yang dibagikan dan ditulis oleh satu versi Python dapat disusun ulang oleh versi lainnya. Anda dapat menemukan panduan cara menerapkan kompatibilitas acar lintas versi di panduan.

Secara default, Python 3 menggunakan protokol pengacakan yang tidak didukung di Python 2. Hal ini dapat menyebabkan kegagalan saat aplikasi Anda mencoba merekonstruksi objek Python di lingkungan Python 2 yang ditulis di lingkungan Python 3. Untuk menghindari masalah ini, tetapkan variabel lingkungan berikut dalam file app.yaml untuk aplikasi Python 3 Anda sesuai kebutuhan:

  • Untuk aplikasi yang menggunakan Memcache termasuk aplikasi yang menggunakan NDB, tetapkan: MEMCACHE_USE_CROSS_COMPATIBLE_PROTOCOL: 'True'
  • Untuk aplikasi yang menggunakan NDB untuk terhubung ke Datastore, tetapkan: NDB_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True'
  • Untuk aplikasi yang menggunakan penangguhan, setel: DEFERRED_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True'

Di Python 2, objek string menyimpan urutan nilai byte 8 bit. Di Python 3, objek string menyimpan urutan karakter unicode. Secara default, software Python 3 akan menerjemahkan string Python 2 menjadi unicode dengan menafsirkan Python 3 string sebagai ASCII. Hal ini dapat menyebabkan error untuk nilai di luar rentang karakter ASCII, yaitu 0 hingga 127. Memcache mendukung penggantian pemetaan default ini.

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))

Encoding latin1, menentukan pemetaan untuk setiap 256 kemungkinan nilai dari setiap byte dalam string Python 2. Tindakan ini mencegah error decoding. Namun, jika string Python 2 Anda berisi data unicode aktual di luar rentang latin1, seperti data yang dibaca dari file, c Pickle tidak akan memetakan data dengan benar. Oleh karena itu, Anda harus memperbarui kode Python 2 untuk menyimpan data unicode dengan objek unicode, bukan objek string, untuk objek yang Anda pilih. Panduan kompatibilitas menyertakan detail tentang update yang diperlukan.

Metode yang dijelaskan sebelumnya untuk memperbarui kode Python 2 guna menghasilkan serialisasi yang kompatibel dengan Python 3 membahas serialisasi jangka pendek, seperti yang disimpan di Memcache. Anda mungkin perlu memperbarui atau menulis ulang serialisasi Python 2 yang aktif dalam waktu lama, seperti yang disimpan di Datastore sebagai bagian dari migrasi Anda. Misalnya, serialisasi yang ditulis menggunakan google.appengine.ext.ndb.model.PickleProperty mungkin memerlukan upgrade.

Lihat panduan kompatibilitas untuk mempelajari lebih lanjut batasan dan masalah yang jarang terjadi.

Framework web

webapp2 tidak dipaketkan atau didukung di Python 3, sehingga aplikasi apa pun harus ditulis ulang untuk menggunakan framework yang kompatibel dengan WSGI (seperti Flask).

Strategi migrasi yang direkomendasikan adalah mengganti penggunaan webapp2 di aplikasi Python 2.7 Anda terlebih dahulu dengan Flask (atau framework web alternatif seperti Django, Pyramid, Bottle, atau web.py), sembari tetap menggunakan Python 2.7. Kemudian, setelah aplikasi yang diupdate sudah stabil, migrasikan kode ke Python 3 lalu deploy dan uji menggunakan App Engine untuk Python 3.

Untuk contoh cara mengonversi aplikasi Python 2.7 yang menggunakan webapp2 untuk menggunakan framework Flask, Anda dapat melihat referensi tambahan ini.

Menggunakan pengendali

Aplikasi Python 3 hanya dapat memiliki satu skrip yang terkait dengannya, jadi jika app.yaml Anda memiliki beberapa pengendali script yang memetakan URL ke skrip yang berbeda, Anda harus menggabungkan skrip tersebut menjadi satu skrip yang menangani routing URL.

Contoh berikut menunjukkan perbedaan pengendali dalam file app.yaml untuk masing-masing runtime.

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

Aplikasi Python 3 Anda harus menangani perutean URL (misalnya, dengan dekorator Flask).

Jika Anda ingin menggunakan beberapa pengendali script dengan pola URL yang berbeda, atau jika ingin menggunakan atribut lain dalam pengendali, setiap pengendali harus menentukan script: auto.

Anda juga dapat mengganti perilaku startup default dengan menentukan kolom entrypoint dalam file app.yaml.

Lihat ringkasan Blobstore, Ditangguhkan, dan Email untuk mengetahui informasi selengkapnya tentang cara menggunakan pengendali tertentu.

Keamanan thread

Aplikasi dianggap aman untuk thread. Panggilan API harus dilakukan pada thread permintaan. Jika Anda menggunakan API layanan paket lama saat aplikasi dimulai, hal ini dapat menyebabkan error keamanan.

Untuk mempelajari lebih lanjut, lihat Error keamanan saat menggunakan layanan paket lama untuk Python.

Menggunakan URL Fetch

Agar dapat menggunakan URL Fetch untuk Python, Anda perlu memanggil library URL Fetch secara eksplisit.

Jika aplikasi Python 3 Anda menggunakan URL Fetch API, header permintaan X-Appengine-Inbound-Appid akan ditambahkan saat aplikasi Anda mengirim permintaan ke aplikasi App Engine lain. Hal ini memungkinkan aplikasi penerima memverifikasi identitas aplikasi panggilan. Untuk mempelajari lebih lanjut, lihat Memigrasikan permintaan keluar.

Contoh (App Engine ndb)

Di bawah ini adalah aplikasi Python 2 dasar yang mendaftarkan kunjungan halaman menggunakan App Engine ndb untuk mengakses Datastore. Pendampingnya adalah aplikasi yang setara dengan Python 3 di mana penggunaan webapp2 telah diganti dengan Flask, dan perubahan yang diperlukan yang dijelaskan di atas untuk mengakses layanan yang dipaketkan di Python 3 telah diterapkan.

Python 2 (webapp2)

import os
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.webapp import template

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

class MainHandler(webapp2.RequestHandler):
    'main application (GET) handler'
    def get(self):
        store_visit(self.request.remote_addr, self.request.user_agent)
        visits = fetch_visits(10)
        tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(tmpl, {'visits': visits}))

app = webapp2.WSGIApplication([
    ('/', MainHandler),
], debug=True)

Python 3 (Flask)

from flask import Flask, render_template, request
from google.appengine.api import wrap_wsgi_app
from google.appengine.ext import ndb

app = Flask(__name__)
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)


class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)


@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

Kedua aplikasi ini dapat ditemukan di repo open source untuk konten migrasi Python App Engine (contoh kode, video, codelab ), khususnya dalam masing-masing folder mod0 dan mod1b.