使用Python 3在AWS lambda上出现sqlite3错误

时间:2017-05-18 21:43:39

标签: python-3.x amazon-web-services sqlite aws-lambda

我正在构建python 3.6 AWS Lambda部署程序包,但遇到了SQLite的问题。

在我的代码中,我使用的nltk在其中一个文件中有import sqlite3

到目前为止的步骤:

  1. 部署包只有我在root用户使用的python模块。我收到错误: Unable to import module 'my_program': No module named '_sqlite3'

  2. /home/my_username/anaconda2/envs/py3k/lib/python3.6/lib-dynload/_sqlite3.so中的_sqlite3.so添加到包根目录中。然后我的错误改为:

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

  3. sqlite.org的SQLite预编译二进制文件添加到我的程序包的根目录中,但我仍然得到错误为#2点。

  4. 我的设置:Ubuntu 16.04python3 virtual env

    AWS lambda env:python3

    如何解决此问题?

8 个答案:

答案 0 :(得分:32)

根据您对NLTK所做的工作,我可能找到了解决方案。

基本nltk模块导入了许多依赖项,其中许多依赖项未被其功能集的大部分使用。在我的用例中,我只使用nltk.sent_tokenize,它对sqlite3没有任何功能依赖,即使sqlite3作为依赖项导入。

我能够通过更改

让我的代码在AWS Lambda上运行
import nltk

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

这会为sqlitesqlite.dbapi2动态创建空模块。当nltk.corpus.reader.panlex_lite尝试导入sqlite时,它将获取我们的空模块而不是标准库版本。这意味着导入将成功,但这也意味着当nltk尝试使用sqlite模块时,它将失败。

如果您正在使用任何实际依赖于sqlite的功能,我恐怕无法帮助。但是如果你正在尝试使用其他nltk功能并且只需要避免缺少sqlite,那么这种技术可能会有效。

答案 1 :(得分:9)

这有点像黑客攻击,但我已经通过将CentOS 7上的Python 3.6中的_sqlite3.so文件直接放入使用Zappa部署到AWS的项目的根目录来实现这一点。这应该意味着,如果您可以将_sqlite3.so直接包含在ZIP的根目录中,那么它应该有效,因此可以通过cpython中的这一行导入:

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

不漂亮,但它有效。您可以在此处找到_sqlite.so的副本:

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

祝你好运!

答案 2 :(得分:6)

这不是解决方案,但我有解释原因。

Python 3在标准库中支持sqlite(稳定到点知道并且不允许安装pysqlite)。但是,此库要求sqlite开发人员工具(C libs)在运行时位于计算机上。亚马逊的Linux AMI默认没有安装这些,这是AWS Lambda运行的(裸ami实例)。我不确定这是否意味着没有安装sqlite支持,或者只是在添加库之后才会工作,因为我测试的是错误的顺序。

Python 2不支持标准库中的sqlite,你必须使用像pysqlite这样的第三方库来获得支持。这意味着可以更轻松地构建二进制文件,而不依赖于机器状态或路径变量。

我的建议,我已经完成了,如果可以的话,只需在python 2.7中运行该功能(并使你的单元测试更加困难:/)。

由于存在局限性(它是3中融入python的基础库的东西),因此创建一个lambda友好的部署包更加困难。我唯一可以建议的是请求AWS向lambda添加该支持,或者(如果你可以通过nltk实际上使用 sqlite片段而逃脱)通过放置具有适当的空白库来复制anaconda方法和属性但实际上并没有做任何事情。

如果您对后者感到好奇,请查看anaconda安装中的任何fake/_sqlite3文件。这个想法只是为了避免导入错误。

答案 3 :(得分:2)

正如冷漠人所描述的那样,直到亚马逊将sqlite3所需的C库捆绑到用于在lambda上运行Python的AMI之前,才有直接的解决方案。

一种解决方法是使用SQLite的纯Python实现,例如PyDbLite。这就解决了这个问题,因为像这样的库并不需要安装任何特定的C库,只需要安装Python。

不幸的是,如果您使用的是库,而后者又使用sqlite3模块,则无法帮助您。

答案 4 :(得分:1)

我的解决方案可能适用于您,也可能不适用于您(因为它取决于Python 3.5),但希望它可以为类似的问题提供一些启示。

sqlite3附带标准库,但不是使用AWS使用的python3.6构建的,其原因由apathyman和其他答案解释。

快速入侵是将共享对象.so包含在lambda包中:

find ~ -name _sqlite3.so

就我而言:

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

但是,这还不够。你会得到:

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

因为_sqlite3.so是用python3.5构建的,所以它还需要python3.5共享对象。您还需要在软件包部署中使用它:

find ~ -name libpython3.5m.so*

就我而言:

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

如果您使用的是使用python3.6构建的_sqlite3.so,则此解决方案可能无效,因为AWS构建的libpython3.6可能不支持此功能。但是,这只是我的教育猜测。如果有人成功完成,请告诉我。

答案 5 :(得分:1)

TL;DR

虽然不是一个很好的方法,但效果很好。使用pickle module 使用本地系统 将您想要的任何功能转储到单独的文件中。将该文件导出到 AWS 项目目录,从文件加载功能并使用它。

长篇

所以,这是我尝试过的,当我尝试从 stopwords 导入 nltk.corpus 时遇到了同样的问题,但 AWS 不允许我导入它,即使安装它似乎也没有由于相同的错误 _sqlite3 module not found,我可以在 Amazon AMI 上使用。为此,我尝试使用本地系统生成一个文件并将停用词转储到其中。这是代码

# Only for Local System

from nltk.corpus import stopwords
import pickle

stop = list(stopwords.words('English'))
with open('stopwords.pkl', 'wb') as f:
    pickle.dump(stop, f)

现在,我使用 winscp 将此文件导出到 AWS Directory,然后通过从我项目中的文件加载它来使用该功能。

import pickle

# loading trained model
with open('stopwords.pkl', 'rb') as f:
    stop = pickle.load(f)

它工作得很好

答案 6 :(得分:0)

从AusIV的回答中,这个版本适用于AWS Lambda和NLTK,我创建了一个dummysqllite文件来模拟所需的引用。

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)

答案 7 :(得分:0)

您需要sqlite3.so文件(正如其他人所指出的那样),但获取该文件的最可靠方法是从lambci / lambda中可用的(半官方的)AWS Lambda docker映像中拉取。例如,对于Python 3.7,这是一种简单的方法:

首先,让我们从docker映像中获取sqlite3.so(库文件):

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

接下来,我们将使用我们的要求和代码制作一个压缩的可执行文件:

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

最后,我们将库文件添加到图像中:

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

如果您想使用AWS SAM构建/打包,则将其复制到lambda环境包的顶层(即,在其他python文件旁边)。