Accedi ai servizi in bundle legacy per Python 3

In questa pagina viene descritto come installare e utilizzare i servizi in bundle legacy con il runtime Python 3 per dell'ambiente standard. L'app deve accedere ai servizi in bundle tramite l'SDK dei servizi App Engine per Python 3.

Prima di iniziare

Installazione dell'SDK dei servizi App Engine

Per installare l'SDK dei servizi App Engine, segui questi passaggi:

  1. Includi l'SDK nella tua app aggiungendo la seguente riga alla tua File requirements.txt:

    appengine-python-standard>=1.0.0
    

    Puoi trovare l'SDK su GitHub nella appengine-python-standard repository e su PyPI.

  2. Aggiungi il seguente codice nello script Python principale. Questo codice crea WSGI middleware che imposta le variabili necessarie per abilitare le chiamate API.

    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)
    

    Piramide

    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. Aggiungi la seguente riga a app.yaml prima di eseguire il deployment dell'app:

    app_engine_apis: true
    
  4. Per eseguire il deployment della tua app, utilizza gcloud app deploy .

Considerazioni sulla migrazione

Se esegui la migrazione a un'istanza, tieni presente quanto segue il runtime Python 3 e la tua app utilizza in bundle legacy.

Test

Per testare localmente la funzionalità dei servizi in bundle legacy nel tuo nell'app Python 3, utilizza server di sviluppo locale. Quando esegui il comando dev_appserver.py, devi impostare la classe Argomento --runtime_python_path per includere un percorso all'interprete Python 3. Ad esempio:

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

Puoi anche impostare l'argomento su un elenco separato da virgole di [RUNTIME_ID]=[PYTHON_INTERPRETER_PATH] coppie. Ad esempio:

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

Compatibilità con sottaceti

Servizi condivisi tra cui Memcache, Cloud NDB e differito utilizzare il modulo pickle per serializzare e condividere gli oggetti Python. Se il tuo ambiente App Engine utilizza sia Python 2 che Python 3, comune durante una migrazione, devi assicurarti che gli oggetti serializzati condivisi scritti da una versione di Python possono essere ricostituito dall'altro. Puoi trovare indicazioni sull'implementazione di più versioni compatibilità con sottaceti .

Per impostazione predefinita, Python 3 utilizza protocolli di pickling che non sono supportati in Python 2. Ciò può causare errori quando l'app tenta di ricostituire un oggetto Python in un ambiente Python 2 scritto in un ambiente Python 3. Per evitare questo problema, imposta quanto segue variabili di ambiente nel file app.yaml dell'app Python 3 in base alle esigenze:

  • Per le app che utilizzano Memcache, incluse quelle che utilizzano NDB, imposta: MEMCACHE_USE_CROSS_COMPATIBLE_PROTOCOL: 'True'
  • Per le app che utilizzano NDB per la connessione a Datastore, imposta: NDB_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True'
  • Per le app che utilizzano il pagamento differito, imposta: DEFERRED_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True'

In Python 2, gli oggetti string contengono una sequenza di valori byte a 8 bit. In Python 3, string oggetti contengono una sequenza di caratteri Unicode. Per impostazione predefinita, Python 3 pickle traduce un string di Python 2 in Unicode mediante l'interpretazione di Python 3 string in formato ASCII. Questo può causare errori per i valori al di fuori del campo ASCII un intervallo di caratteri compreso tra 0 e 127. Memcache supporta l'override di questa mappatura predefinita.

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

La codifica latin1 definisce una mappatura per ciascuno dei 256 valori possibili di ogni byte in un string Python 2. In questo modo si evitano errori di decodifica. Tuttavia, se il tuo string Python 2 contiene dati Unicode effettivi al di fuori di latin1 ad esempio i dati letti da un file, cPickle non mapperà i dati in modo corretto. Pertanto, è importante aggiornare il codice Python 2 in modo che dati Unicode con unicode oggetti e non string oggetti, per gli oggetti Sottaceto. La compatibilità guide include dettagli su gli aggiornamenti necessari.

Il metodo descritto in precedenza per aggiornare il codice Python 2 al fine di produrre Python Tre serializzazioni compatibili sono rivolte a serializzazioni di breve durata, come archiviati in Memcache. Potresti dover aggiornare o riscrivere il codice Python 2 di lunga durata. serializzazioni, come quelle archiviate in Datastore come parte migrazione. Ad esempio, serializzazione scritta utilizzando google.appengine.ext.ndb.model.PickleProperty potrebbe richiedere un upgrade.

Consulta la guida alla compatibilità per scoprire di più sulle limitazioni e sui problemi meno comuni.

Framework web

webapp2 non è in bundle o supportato in Python 3, quindi qualsiasi applicazione deve essere riscritte per utilizzare qualsiasi framework compatibile con WSGI (come Flask).

Una strategia di migrazione consigliata è quella di sostituire prima l'utilizzo di webapp2 in l'app Python 2.7 con Flask (o un framework web alternativo come Django Piramide Bottiglia oppure web.py), rimanendo su Python 2.7. Quindi, quando l'app aggiornata è stabile, esegui la migrazione del codice a Python 3 e eseguire il deployment e testare utilizzando App Engine per Python 3.

Per esempi di come convertire app Python 2.7 che utilizzano webapp2 per utilizzare il framework Flask, puoi fare riferimento queste risorse aggiuntive.

Utilizzare i gestori

Un'app Python 3 può avere un solo script associato, quindi se il tuo app.yaml ha più gestori script che mappano gli URL a script diversi, dovrai combinare questi script in un unico script che gestisca il routing degli URL.

L'esempio seguente mostra le differenze relative ai gestori nel file app.yaml per i rispettivi 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

L'app Python 3 deve gestire il routing degli URL (ad esempio, con Decoratori di Flask).

Se vuoi utilizzare più gestori script con pattern URL diversi, oppure se vuoi utilizzare altri attributi nei tuoi gestori, ogni gestore deve specificare script: auto.

Puoi anche eseguire l'override del comportamento di avvio predefinito specificare un campo entrypoint nel file app.yaml.

Visita il Blobstore. Rinviato e Posta per ulteriori informazioni sull'utilizzo di gestori specifici.

Sicurezza dei thread

Si presume che le app siano sicure per i thread. Le chiamate API devono essere effettuate nella richiesta . Se utilizzi un'API dei servizi in bundle legacy quando l'app viene questo può causare errori di sicurezza.

Per saperne di più, consulta Errori di sicurezza quando si utilizzano servizi in bundle legacy per Python.

Utilizzo del recupero URL

Per utilizzare il metodo di recupero URL per Python, devi chiamare in modo esplicito il metodo nella libreria di recupero URL.

Se la tua app Python 3 utilizza l'API URL Fetch, X-Appengine-Inbound-Appid l'intestazione della richiesta viene aggiunta quando la tua app invia una richiesta a un'altra dell'app App Engine. In questo modo l'app ricevente può verificare la chiamata l'identità dell'app. Per saperne di più, vedi Migrazione delle richieste in uscita.

Esempio (App Engine ndb)

Di seguito è riportata un'app Python 2 di base che registra le visite alle pagine utilizzando App Engine ndb per accedere a Datastore. L'altra app complementare è un'app equivalente Python 3 in cui webapp2 è stato sostituito da Flask e le modifiche richieste descritte sopra per l'accesso ai servizi in bundle in Python 3 è stato implementato.

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)

Entrambe queste app sono disponibili nell'open source repo di comando Contenuti sulla migrazione di App Engine (esempi di codice, video, codelabs), in particolare nella sezione mod0 e mod1b cartelle.