web-dev-qa-db-fra.com

erreur sqlite3 sur AWS lambda avec Python 3

Je construis un package python 3.6 AWS Lambda deploy et je rencontrais un problème avec SQLite.

Dans mon code, j'utilise nltk qui a un import sqlite3 dans l'un des fichiers.

Mesures prises jusqu'à maintenant:

  1. Le package de déploiement ne contient que des modules python que j'utilise à la racine. J'ai l'erreur: Unable to import module 'my_program': No module named '_sqlite3'

  2. Ajout du _sqlite3.so de /home/my_username/anaconda2/envs/py3k/lib/python3.6/lib-dynload/_sqlite3.so dans le paquet root. Puis mon erreur s'est transformée en:

    Unable to import module 'my_program': dynamic module does not define module export function (PyInit__sqlite3)

  3. Ajout des binaires précompilés SQLite de sqlite.org à la racine de mon paquet, mais le message d'erreur n ° 2 persiste.

Ma configuration: Ubuntu 16.04, python3 virtual env

AWS lambda env: python3

Comment puis-je résoudre ce problème?

20
darthsidious

En fonction de ce que vous faites avec NLTK, j'ai peut-être trouvé une solution. 

Le module nltk de base importe de nombreuses dépendances, dont beaucoup ne sont pas utilisées par des parties substantielles de son ensemble de fonctionnalités. Dans mon cas d'utilisation, j'utilise uniquement le nltk.sent_tokenize, qui ne comporte aucune dépendance fonctionnelle sur sqlite3, même si sqlite3 est importé en tant que dépendance.

J'ai pu faire fonctionner mon code sur AWS Lambda en changeant

import nltk

à 

import imp
import sys
sys.modules["sqlite"] = imp.new_module("sqlite")
sys.modules["sqlite3.dbapi2"] = imp.new_module("sqlite.dbapi2")
import nltk

Cela crée dynamiquement des modules vides pour sqlite et sqlite.dbapi2. Lorsque nltk.corpus.reader.panlex_lite tente d'importer sqlite, il obtiendra notre module vide à la place de la version standard de la bibliothèque. Cela signifie que l'importation réussira, mais cela signifie également que si nltk essaie d'utiliser le module sqlite, il échouera.

Si vous utilisez des fonctionnalités qui dépendent réellement de sqlite, j'ai bien peur de ne pouvoir vous aider. Mais si vous essayez d’utiliser d’autres fonctionnalités de nltk et que vous avez juste besoin de pallier le manque de sqlite, cette technique peut fonctionner.

28
AusIV

C'est un peu un bidouillage, mais j'ai réussi à le faire en déposant le fichier _sqlite3.so de Python 3.6 sur CentOS 7 directement dans la racine du projet en cours de déploiement avec Zappa vers AWS. Cela devrait signifier que si vous pouvez inclure _sqlite3.so directement dans la racine de votre zip, cela devrait fonctionner, afin qu'il puisse être importé par cette ligne dans cpython:

https://github.com/python/cpython/blob/3.6/Lib/sqlite3/dbapi2.py#L27

Pas joli, mais ça marche. Vous pouvez trouver une copie de _sqlite.so ici:

https://github.com/Miserlou/lambda-packages/files/1425358/_sqlite3.so.Zip

Bonne chance!

8
FlipperPA

Ce n'est pas une solution, mais j'ai une explication pourquoi.

Python 3 prend en charge sqlite dans la bibliothèque standard (stable au point de savoir pip et ne permettant pas l’installation de pysqlite). Cependant, cette bibliothèque nécessite que les outils de développement sqlite (bibliothèques C) se trouvent sur la machine au moment de l'exécution. AMI Linux d’Amazon ne les a pas installés par défaut, ce sur quoi AWS Lambda est exécuté (instances AMI nues). Je ne sais pas si cela signifie que le support de SQLite n'est pas installé ou ne fonctionnera tout simplement pas tant que les bibliothèques ne seront pas ajoutées, car j'ai testé les choses dans le mauvais ordre.

Python 2 ne prend pas en charge sqlite dans la bibliothèque standard, vous devez utiliser une bibliothèque tierce, telle que pysqlite, pour obtenir ce support. Cela signifie que les fichiers binaires peuvent être construits plus facilement sans dépendre de l'état de la machine ou des variables de chemin d'accès. 

Ma suggestion, que vous avez déjà faite, à mon avis, consiste simplement à exécuter cette fonction dans python 2.7 si vous le pouvez (et à rendre votre test unitaire d'autant plus difficile: /).

En raison des limitations (c’est quelque chose qui a été cuit dans les bibliothèques de base de python dans 3), il est plus difficile de créer un package de déploiement convivial pour lambda. La seule chose que je peux suggérer est de demander à AWS d’ajouter ce support à lambda ou (si vous pouvez vous en échapper sans utiliser using the sqlite pieces in nltk) de copier anaconda en mettant des bibliothèques vierges dotées des méthodes et attributs appropriés. mais ne fait vraiment rien.

Si vous êtes curieux de savoir ce dernier point, consultez l’un des fichiers fake/_sqlite3 dans une installation anaconda. L'idée est seulement d'éviter les erreurs d'importation.

6
apathyman

Comme Apathyman l'a décrit, il n'y a pas de solution directe à ce problème avant qu'Amazon regroupe les bibliothèques C requises pour sqlite3 dans les AMI utilisées pour exécuter Python sur lambda.

Une solution de contournement consiste à utiliser une implémentation Python pure de SQLite, telle que PyDbLite . Cela soulève le problème, car une bibliothèque comme celle-ci ne nécessite pas l'installation de bibliothèques C particulières, mais uniquement de Python.

Malheureusement, cela ne vous aide pas si vous utilisez une bibliothèque qui utilise à son tour le module sqlite3.

2
majackson

Ma solution peut ou non s’appliquer à vous (car elle dépend de Python 3.5), mais nous espérons qu’elle éclaircira un problème similaire.

sqlite3 est fourni avec la bibliothèque standard, mais n'est pas construit avec le python3.6 utilisé par AWS, avec la raison expliquée par apathyman et d'autres réponses.

Le hack rapide consiste à inclure l'objet de partage .so dans votre paquet lambda:

find ~ -name _sqlite3.so

Dans mon cas:

/home/user/anaconda3/pkgs/python-3.5.2-0/lib/python3.5/lib-dynload/_sqlite3.so

Cependant, cela ne suffit pas totalement. Tu auras: 

ImportError: libpython3.5m.so.1.0: cannot open shared object file: No such file or directory

Étant donné que _sqlite3.so est construit avec python3.5, il nécessite également un objet partagé python3.5. Vous en aurez également besoin dans le déploiement de votre paquet:

find ~ -name libpython3.5m.so*

Dans mon cas:

/home/user/anaconda3/pkgs/python-3.5.2-0/lib/libpython3.5m.so.1.0

Cette solution ne fonctionnera probablement pas si vous utilisez _sqlite3.so construit avec python3.6, car libpython3.6 construit par AWS ne le supportera probablement pas. Cependant, ceci est juste ma conjecture éducative. Si quelqu'un a réussi, faites-le moi savoir.

1
bizi

Vous avez besoin du fichier sqlite3.so (comme d'autres l'ont déjà souligné), mais le moyen le plus sûr de l'obtenir est d'extraire des images (semi-officielles?) Du menu fixe AWS Lambda disponibles dans lambci/lambda. Par exemple, pour Python 3.7, voici un moyen simple de procéder:

Tout d’abord, prenons le sqlite3.so (fichier de bibliothèque) à partir de l’image de menu fixe:

mkdir lib
docker run -v $PWD:$PWD lambci/lambda:build-python3.7 bash -c "cp sqlite3.cpython*.so $PWD/lib/"

Ensuite, nous allons créer un exécutable compressé avec nos exigences et notre code:

pip install -t output requirements.txt
pip install . -t output
Zip -r output.Zip output

Enfin, nous ajoutons le fichier de bibliothèque à notre image:

cd lib && Zip -r ../output.Zip sqlite3.cpython*.so

Si vous souhaitez utiliser AWS SAM build/packaging, copiez-le plutôt dans le niveau supérieur du package d'environnement lambda (c'est-à-dire, à côté de vos autres fichiers python).

0
Jeff Tratner

D'après la réponse d'AusIV, cette version fonctionne pour AWS Lambda et NLTK, j'ai créé un fichier factice afin de simuler les références requises. 

spec = importlib.util.spec_from_file_location("_sqlite3","/dummysqllite.py")
sys.modules["_sqlite3"] = importlib.util.module_from_spec(spec)
sys.modules["sqlite3"] = importlib.util.module_from_spec(spec)
sys.modules["sqlite3.dbapi2"] = importlib.util.module_from_spec(spec)