python 3.x - Error de sqlite3 en AWS lambda con Python 3
python-3.x amazon-web-services (6)
Estoy construyendo un paquete de implementación AWS Lambda de python 3.6
y me enfrenté a un problema con SQLite
.
En mi código estoy usando nltk
que tiene un import sqlite3
en uno de los archivos.
Pasos tomados hasta ahora:
El paquete de implementación solo tiene módulos de Python que estoy usando en la raíz. Recibo el error:
Unable to import module ''my_program'': No module named ''_sqlite3''
Agregue el _sqlite3.so desde
/home/my_username/anaconda2/envs/py3k/lib/python3.6/lib-dynload/_sqlite3.so
en la raíz del paquete. Entonces mi error cambió a:Unable to import module ''my_program'': dynamic module does not define module export function (PyInit__sqlite3)
sqlite.org
binarios precompilados de SQLite desqlite.org
a la raíz de mi paquete, pero aún obtengo el error como punto # 2.
Mi configuración: Ubuntu 16.04
, python3 virtual env
AWS lambda env: python3
¿Como puedo solucionar este problema?
A partir de la respuesta de AusIV, esta versión me funciona en AWS Lambda y NLTK, creé un archivo dummysqllite para simular las referencias requeridas.
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)
Como lo describe apathyman, no hay una solución directa a esto hasta que Amazon agrupe las bibliotecas de C requeridas para sqlite3
en las AMI utilizadas para ejecutar Python en lambda.
Sin embargo, una solución es utilizar una implementación Python pura de SQLite, como PyDbLite . Esto evita el problema, ya que una biblioteca como esta no requiere que se instale ninguna biblioteca C en particular, solo Python.
Desafortunadamente, esto no le ayuda si está usando una biblioteca que a su vez usa el módulo sqlite3
.
Dependiendo de lo que esté haciendo con NLTK, es posible que haya encontrado una solución.
El módulo base nltk importa muchas dependencias, muchas de las cuales no son utilizadas por partes sustanciales de su conjunto de características. En mi caso de uso, solo uso nltk.sent_tokenize
, que no tiene dependencia funcional en sqlite3, aunque sqlite3 se importa como una dependencia.
Pude obtener mi código trabajando en AWS Lambda cambiando
import nltk
a
import imp
import sys
sys.modules["sqlite"] = imp.new_module("sqlite")
sys.modules["sqlite3.dbapi2"] = imp.new_module("sqlite.dbapi2")
import nltk
Esto crea dinámicamente módulos vacíos para sqlite
y sqlite.dbapi2
. Cuando nltk.corpus.reader.panlex_lite
intenta importar sqlite
, obtendrá nuestro módulo vacío en lugar de la versión estándar de la biblioteca. Eso significa que la importación tendrá éxito, pero también significa que cuando nltk intente usar el módulo sqlite fallará.
Si estás usando alguna funcionalidad que realmente dependa de sqlite, me temo que no puedo ayudarte. Pero si está intentando usar otra funcionalidad nltk y solo necesita evitar la falta de sqlite, esta técnica podría funcionar.
Esto es un poco difícil, pero he conseguido que esto funcione al colocar el archivo _sqlite3.so
de Python 3.6 en CentOS 7 directamente en la raíz del proyecto que se implementa con Zappa en AWS. Esto debería significar que si puede incluir _sqlite3.so
directamente en la raíz de su ZIP, debería funcionar, por lo que puede ser importado por esta línea en cpython
:
https://github.com/python/cpython/blob/3.6/Lib/sqlite3/dbapi2.py#L27
No es bonita, pero funciona. Puedes encontrar una copia de _sqlite.so
aquí:
https://github.com/Miserlou/lambda-packages/files/1425358/_sqlite3.so.zip
¡Buena suerte!
Esto no es una solución, pero tengo una explicación de por qué.
Python 3 tiene soporte para sqlite en la biblioteca estándar (estable hasta el punto de conocimiento de pip y no permite la instalación de pysqlite). Sin embargo, esta biblioteca requiere que las herramientas de desarrollo de sqlite (C libs) estén en la máquina en tiempo de ejecución. La AMI linux de Amazon no tiene estas instaladas de manera predeterminada, que es en lo que se ejecuta AWS Lambda (instancias ami desnudas). No estoy seguro si esto significa que el soporte de sqlite no está instalado o simplemente no funcionará hasta que se agreguen las bibliotecas, sin embargo, porque probé las cosas en el orden incorrecto.
Python 2 no admite sqlite en la biblioteca estándar, tiene que usar una librería de terceros como pysqlite para obtener ese soporte. Esto significa que los binarios se pueden construir más fácilmente sin depender del estado de la máquina o de las variables de ruta.
Mi sugerencia, que ya has hecho, veo, es simplemente ejecutar esa función en Python 2.7 si puedes (y hacer que tu prueba de unidad sea mucho más difícil: /).
Debido a las limitaciones (es algo que se incluye en las bibliotecas base de python en 3) es más difícil crear un paquete de implementación compatible con lambda. Lo único que puedo sugerir es solicitar a AWS que agregue ese soporte a lambda o (si puede alejarse sin usar las piezas de sqlite en nltk) copiando anaconda colocando bibliotecas en blanco que tengan los métodos y atributos adecuados pero no En realidad hacer cualquier cosa.
Si tienes curiosidad por esto último, echa un vistazo a cualquiera de los archivos fake/_sqlite3
en una instalación de anaconda. La idea es sólo para evitar errores de importación.
Mi solución puede o no aplicarse a ti (ya que depende de Python 3.5), pero espero que pueda arrojar algo de luz para un problema similar.
sqlite3
viene con una biblioteca estándar, pero no está construido con el python3.6 que usa AWS, con la razón explicada por apathyman
y otras respuestas.
El truco rápido es incluir el objeto compartido .so
en su paquete lambda:
find ~ -name _sqlite3.so
En mi caso:
/home/user/anaconda3/pkgs/python-3.5.2-0/lib/python3.5/lib-dynload/_sqlite3.so
Sin embargo, eso no es totalmente suficiente. Conseguirás:
ImportError: libpython3.5m.so.1.0: cannot open shared object file: No such file or directory
Debido a que _sqlite3.so
está construido con python3.5, también requiere el objeto compartido python3.5. También necesitarás eso en el despliegue de tu paquete:
find ~ -name libpython3.5m.so*
En mi caso:
/home/user/anaconda3/pkgs/python-3.5.2-0/lib/libpython3.5m.so.1.0
Es probable que esta solución no funcione si está utilizando _sqlite3.so
que está construido con python3.6, porque es probable que el libpython3.6 creado por AWS no sea compatible con esto. Sin embargo, esta es solo mi conjetura educativa. Si alguien lo ha hecho con éxito, por favor hágamelo saber.