Quelle est la meilleure stratégie pour gérer des bibliothèques tierces Python avec Google App Engine?
Disons que je veux utiliser Flask, un framework webapp. ne entrée de blog dit de faire cela, ce qui ne semble pas correct:
$ cd /tmp/
$ wget http://pypi.python.org/packages/source/F/Flask/Flask-0.6.1.tar.gz
$ tar zxf Flask-0.6.1.tar.gz
$ cp -r Flask-0.6.1/flask ~/path/to/project/
(... repeat for other packages ...)
Il doit y avoir un meilleur moyen de gérer le code tiers, surtout si je veux suivre les versions, tester les mises à niveau ou si deux bibliothèques partagent un sous-répertoire. Je sais que Python peut importer des modules à partir de fichiers zip et que pip peut fonctionner avec un merveilleux fichier REQUIREMENTS, et je ' J'ai vu que pip a une commande Zip
à utiliser avec GAE.
(Remarque: il existe une poignée de questions similaires - 1 , 2 , , 4 , 5 - mais ils sont spécifiques à chaque cas et ne répondent pas vraiment à ma question.)
Et tout simplement:
$ pip install -r requirements.txt -t <your_app_directory/lib>
Créer/modifier <your_app_directory>/appengine_config.py
:
"""This file is loaded when starting a new application instance."""
import sys
import os.path
# add `lib` subdirectory to `sys.path`, so our `main` module can load
# third-party libraries.
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'lib'))
Google a mis à jour son exemple en appengine_config.py
, comme:
from google.appengine.ext import vendor
vendor.add('lib')
Remarque: Même si leur exemple a .gitignore
ignorant lib/
répertoire dont vous avez besoin pour conserver ce répertoire sous contrôle de code source si vous utilisez git-Push
méthode de déploiement.
Voici comment je le fais:
Le répertoire project
est le répertoire de niveau supérieur où se trouve virtualenv. J'obtiens le virtualenv en utilisant les commandes suivantes:
cd project
virtualenv -p /usr/bin/python2.5 --no-site-packages --distribute .
Le répertoire src
est l'endroit où va tout votre code. Lorsque vous déployez votre code vers GAE, * uniquement * déployez-les dans le répertoire src et rien d'autre. Le appcfg.py
résoudra les liens symboliques et copiera les fichiers de bibliothèque dans GAE pour vous.
Je n'installe pas mes bibliothèques en tant que fichiers Zip principalement pour des raisons de commodité au cas où j'aurais besoin de lire le code source, ce que je fais beaucoup par curiosité. Cependant, si vous voulez vraiment compresser les bibliothèques, mettez l'extrait de code suivant dans votre main.py
import sys
for p in ['librarie.Zip', 'package.Egg'...]:
sys.path.insert(0, p)
Après cela, vous pouvez importer vos paquets zippés comme d'habitude.
Une chose à surveiller est le setuptools 'pkg_resources.py
. J'ai copié cela directement dans mon répertoire src
pour que mes autres packages avec lien symbolique puissent l'utiliser. Attention à tout ce qui utilise entry_point
s. Dans mon cas, j'utilise Toscawidgets2 et j'ai dû creuser dans le code source pour câbler manuellement les morceaux. Cela peut devenir ennuyeux si vous avez beaucoup de bibliothèques qui dépendent de entry_point
.
Je préfère buildout .
Vous configurez des dépendances dans setup.py dans votre projet ou buildout.cfg, épinglez les versions dans buildout.cfg et spécifiez quels packages ne sont pas disponibles sur GAE et doivent être inclus dans packages.Zip. rod.recipe.appengine copiera les packages requis dans packages.Zip, et tant que vous insérez packages.Zip dans sys.path, ils peuvent être importés n'importe où.
Vous pouvez également utiliser des fourches de github si le package dont vous avez besoin n'est pas sur pypi
find-links =
https://github.com/tesdal/pusher_client_python/tarball/rewrite#Egg=pusher-2.0dev2
[versions]
pusher = 2.0dev2
et tous ces paramètres et dépendances sont versionnés dans git.
Au lieu de vous demander quelle copie de Flask est actuellement incluse dans votre arborescence source et peut-être copiée dans votre contrôle de version (ou oblige les nouveaux développeurs à décompresser et à mettre à niveau manuellement), vous vérifiez simplement la version dans buildout. cfg. Si vous voulez une nouvelle version, changez buildout.cfg et relancez buildout.
Vous pouvez également l'utiliser pour insérer des variables dans des modèles de fichiers de configuration, comme définir l'ID et la version de appspot dans app.yaml si vous disposez d'un serveur de transfert avec staging.cfg, etc.
J'ai récemment créé un outil pour cela appelé gaenv. Il suit un format requirements.txt, mais ne l'installe pas, vous pouvez installer avec pip install -r requirements.txt puis exécuter l'outil de ligne de commande gaenv.
$ pip install -r requirements.txt
$ gaenv
Cela crée automatiquement des liens symboliques, vous pouvez également installer gaenv dans votre virtualenv et exécuter le binaire à partir de là. Voici un article de blog à ce sujet:
http://blog.altlimit.com/2013/06/google-app-engine-virtualenv-tool-that.html
également sur github
la solution de Wernight est la plus proche de la pratique actuelle dans officiel Flask exemple d'application , que j'ai déjà amélioré en changeant la fonction sys.path.insert()
appel à site.addsitedir()
afin de permettre packages d'espaces de noms en traitant leurs fichiers .pth
(qui sont importants pour les frameworks comme Pyramid).
Jusqu'à présent tout va bien, mais cela ajoute le répertoire au chemin, et perd ainsi la possibilité de remplacer les bibliothèques incluses (comme WebOb et les requêtes) par des nouvelles versions.
Ce qui est alors nécessaire dans appengine_config.py
(Et j'essaie de faire accepter ce changement dans les dépôts officiels) est le suivant:
"""This file is loaded when starting a new application instance."""
import os.path
import site.addsitedir
import sys.path
dirname = 'lib'
dirpath = os.path.join(os.path.dirname(__file__), dirname)
# split path after 1st element ('.') so local modules are always found first
sys.path, remainder = sys.path[:1], sys.path[1:]
# add `lib` subdirectory as a site directory, so our `main` module can load
# third-party libraries.
site.addsitedir(dirpath)
# append the rest of the path
sys.path.extend(remainder)
La version finale de ce code peut finir cachée dans un module vendor.py
Et appelée comme insertsitedir(index, path)
ou une autre variante, comme vous pouvez le voir dans la discussion concernant cette pull request , mais la logique est plus ou moins comment cela fonctionnera de toute façon, pour permettre à un simple pip install -r requirements.txt -t lib/
de fonctionner pour tous les packages, y compris ceux de l'espace de noms, et pour permettre toujours de remplacer les bibliothèques incluses avec de nouvelles versions, comme je ont été jusqu'à présent impossible de trouver une alternative plus simple .
Remarque: cette réponse est spécifique à Flask sur Google App Engine.
Reportez-vous au projet flask-appengine-template pour voir comment obtenir les extensions Flask pour fonctionner sur App Engine. https://github.com/kamalgill/flask-appengine- modèle
Déposez l'extension dans le dossier de package d'espace de noms à src/packages/flaskext et vous êtes prêt. https://github.com/kamalgill/flask-appengine-template/tree/master/src/lib/flaskext
Les packages non-Flask peuvent être déposés dans le dossier src/packages sous forme de fichiers Zip, d'oeufs ou de packages décompressés, car le modèle de projet inclut l'extrait sys.path.insert () publié ci-dessus.