בדף הזה מוסבר איך להתקין ולהשתמש בשירותים מדור קודם שצורפו ל-Python 3 runtime בסביבה הרגילה. האפליקציה שלכם חייבת לגשת לשירותים הכלולים בחבילה באמצעות App Engine services SDK ל-Python 3.
לפני שמתחילים
- אפשר לעיין ברשימת ממשקי ה-API של שירותים מדור קודם שאפשר להפעיל בסביבת זמן הריצה של Python.
- לפני שמתחילים פרויקט העברה ל-Python 3, כדאי לעיין בסקירה הכללית של העברת זמן הריצה ובשיקולים להעברה כשמשתמשים בשירותים קודמים בחבילה.
התקנה של App Engine services SDK
כדי להתקין את App Engine services SDK, פועלים לפי השלבים הבאים:
כדי לכלול את ה-SDK באפליקציה, מוסיפים את השורה הבאה לקובץ
requirements.txt:appengine-python-standard>=1.0.0ערכת ה-SDK זמינה במאגר
appengine-python-standardב-GitHub וב-PyPI.מוסיפים את הקוד הבא לסקריפט ה-Python הראשי. הקוד הזה יוצר תוכנת ביניים של WSGI שמגדירה את המשתנים שנדרשים להפעלת קריאות ה-API.
בקבוקון לשתייה חריפה
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)פירמידה
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_bundled_services: - datastore_v3 - memcache - userאם אתם משתמשים בתכונות כמו
login: adminבקטעhandlersשל קובץapp.yaml, אתם צריכים להפעיל את Users API על ידי הגדרת ההגדרהuserברשימהapp_engine_bundled_services.כדי לפרוס את האפליקציה, משתמשים בפקודה
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 משתמש בפרוטוקולים של pickling שלא נתמכים ב-Python 2.
הדבר עלול לגרום לכשלים כשהאפליקציה מנסה לשחזר אובייקט Python בסביבת Python 2 שנכתבה בסביבת Python 3.
כדי למנוע את הבעיה הזו, צריך להגדיר את משתני הסביבה הבאים בקובץ app.yaml של אפליקציית Python 3 לפי הצורך:
- באפליקציות שמשתמשות ב-Memcache, כולל אפליקציות שמשתמשות ב-NDB, צריך להגדיר:
MEMCACHE_USE_CROSS_COMPATIBLE_PROTOCOL: 'True' - באפליקציות שמשתמשות ב-NDB כדי להתחבר ל-Datastore, צריך להגדיר:
NDB_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True' - באפליקציות שמשתמשות בהתקנה מושהית, מגדירים:
DEFERRED_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True'
ב-Python 2, אובייקטים מסוג string מכילים רצף של ערכי בייט של 8 ביט. ב-Python 3, אובייקטים מסוג string מכילים רצף של תווי Unicode. כברירת מחדל, הפונקציה pickle ב-Python 3 מתרגמת string ב-Python 2 ל-Unicode על ידי פירוש string ב-Python 3 כ-ASCII. זה עלול לגרום לשגיאות בערכים שנמצאים מחוץ לטווח התווים של 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 מגדיר מיפוי לכל אחד מ-256 הערכים האפשריים של כל בייט ב-string של Python 2. כך נמנעים שגיאות פענוח. עם זאת, אם string של Python 2 מכיל נתוני Unicode בפועל מחוץ לטווח latin1, כמו נתונים שנקראו מקובץ, cPickle לא ימפה את הנתונים בצורה נכונה. לכן, חשוב לעדכן את הקוד של Python 2 כך שיכיל נתוני Unicode עם אובייקטים מסוג unicode ולא אובייקטים מסוג string, עבור אובייקטים שאתם מבצעים עליהם Pickling. במדריך בנושא תאימות מפורטים העדכונים הנדרשים.
השיטה שמתוארת למעלה לעדכון קוד Python 2 כדי ליצור סדרות תואמות ל-Python 3 מתייחסת לסדרות לטווח קצר, כמו אלה שמאוחסנות ב-Memcache. יכול להיות שתצטרכו לעדכן או לשכתב סדרות ארוכות של Python 2, כמו אלה שמאוחסנות ב-Datastore כחלק מההעברה. לדוגמה, יכול להיות שיהיה צורך לשדרג סריאליזציה שנכתבה באמצעות google.appengine.ext.ndb.model.PickleProperty.
במדריך התאימות אפשר לקרוא מידע נוסף על מגבלות ועל בעיות פחות נפוצות.
מסגרות אינטרנט
webapp2 לא כלול ב-Python 3 ולא נתמך בו, ולכן צריך לכתוב מחדש כל אפליקציה כדי להשתמש בכל מסגרת תואמת WSGI (כמו Flask).
אסטרטגיית המיגרציה המומלצת היא קודם להחליף את השימוש ב-webapp2 באפליקציית Python 2.7 ב-Flask (או ב-framework חלופי לאינטרנט כמו Django, Pyramid, Bottle או web.py), תוך שמירה על Python 2.7. לאחר מכן, כשהאפליקציה המעודכנת יציבה, מעבירים את הקוד ל-Python 3 ומבצעים פריסה ובדיקה באמצעות App Engine ל-Python 3.
דוגמאות להמרת אפליקציות Python 2.7 שמשתמשות ב-webapp2 לשימוש ב-Flask framework מופיעות במקורות המידע הנוספים האלה.
שימוש באפליקציות ניהול
לאפליקציית Python 3 יכול להיות רק סקריפט אחד שמשויך אליה, ולכן אם בקובץ app.yaml יש כמה פונקציות handler של script שממפות כתובות URL לסקריפטים שונים, תצטרכו לשלב את הסקריפטים האלה לסקריפט אחד שמטפל בניתוב כתובות ה-URL.
בדוגמה הבאה מוצגים ההבדלים בין פונקציות ה-handler בקובץ 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: python314
app_engine_bundled_services:
- datastore_v3
- memcache
- user
...
#list your bundled services
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).
אם רוצים להשתמש בכמה רכיבי handler עם תבניות שונות של כתובות URL, או אם רוצים להשתמש במאפיינים אחרים ברכיבי ה-handler, צריך לציין script: auto בכל רכיב handler.script
אפשר גם לשנות את התנהגות ברירת המחדל של ההפעלה על ידי ציון שדה entrypoint בקובץ app.yaml.
למידע נוסף על אופן השימוש בגורמים מטפלים ספציפיים, אפשר לעיין במאמרים בנושא Blobstore, Deferred ו-Mail.
Thread safety
ההנחה היא שהאפליקציות בטוחות לשימוש עם שרשורים. קריאות ל-API צריכות להתבצע בשרשור הבקשה. אם משתמשים ב-API של שירותים בחבילה מדור קודם כשהאפליקציה מופעלת, עלולות להתרחש שגיאות אבטחה.
מידע נוסף זמין במאמר שגיאות אבטחה בשימוש בחבילות שירותים מדור קודם ל-Python.
שימוש בשירות אחזור של כתובות אתרים
כדי להשתמש ב-URL Fetch ל-Python, צריך לקרוא באופן מפורש לספריית URL Fetch.
אם האפליקציה שלכם ב-Python 3 משתמשת ב-URL Fetch API, כותרת הבקשה X-Appengine-Inbound-Appid מתווספת כשהאפליקציה שולחת בקשה לאפליקציה אחרת ב-App Engine. כך האפליקציה המקבלת יכולה לאמת את הזהות של האפליקציה שקוראת לה. מידע נוסף זמין במאמר בנושא העברת בקשות יוצאות.
דוגמה (App Engine ndb)
למטה מופיעה אפליקציית Python 2 בסיסית שרושמת ביקורים בדף באמצעות App Engine ndb כדי לגשת ל-Datastore. האפליקציה המקבילה היא אפליקציית Python 3 שבה webapp2
השימוש הוחלף ב-Flask, והשינויים הנדרשים שמתוארים למעלה כדי לגשת לשירותים בחבילה ב-Python 3 יושמו.
Python 2 (webapp2)
Python 3 (Flask)
אפשר למצוא את שתי האפליקציות האלה במאגר הקוד הפתוח של תוכן ההעברה של Python App Engine (דוגמאות קוד, סרטונים, שיעורי Codelab), באופן ספציפי בתיקיות mod0 ו-mod1b.