【问题标题】:How to install a Python package on Linux so that it is found by the already working PostgreSQL 13 plpython3u extension?如何在 Linux 上安装 Python 包,以便已经工作的 PostgreSQL 13 plpython3u 扩展可以找到它?
【发布时间】:2021-09-01 11:44:29
【问题描述】:

分拆:

我试图抓住“Module not found” when importing a Python package within a plpython3u procedure 的想法,我不知道如何使用那里接受的答案使其在Linux 上运行。通常,这里应该是重复的,但如果在使用的路径上与 MacOS 有差异,它可能对一个新问题有好处。

安装 PostgreSQL 13

我在 WSL2 (Ubuntu 20.04) 上。我使用来自PostgreSQL Apt Repository for Ubuntu 的官方 PostgreSQL 下载页面的命令进行安装。

# Create the file repository configuration:
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'

# Import the repository signing key:
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

# Update the package lists:
sudo apt-get update

# Install the latest version of PostgreSQL.
# If you want a specific version, use 'postgresql-12' or similar instead of 'postgresql':
sudo apt-get -y install postgresql

这给了我 PostgreSQL 13。

正确安装plpython3u

我用来自PostgreSQL: how to install plpythonu extension的命令安装了plpython3u:

sudo apt-cache search ".*plpython3.*"
sudo apt-get install postgresql-contrib postgresql-plpython3-13

因为我在 WSL 上,所以我用以下方式启动服务:

service postgresql start

更改角色并运行 psql:

sudo su postgres
psql

带有 plpython3u 的 PostgreSQL 安装和测试,无需导入包

在 postgreSQL 中以存储过程的形式直接检查 Python 版本:

CREATE OR REPLACE FUNCTION return_version()
  RETURNS VARCHAR
AS $$
    import sys
    return sys.version
$$ LANGUAGE plpython3u;

输出:

CREATE FUNCTION

测试:

postgres=# SELECT return_version();
              return_version
------------------------------------------
 3.8.10 (default, Jun  2 2021, 10:49:15) +
 [GCC 9.4.0]
(1 row)

显示对于“PostgreSQL 13”,“Python 3.8.10” 已安装。

这正是在 Linux 上可以找到的。如果我只是输入一个我没有的 Python 版本,比如3.7

python3.7

我得到了概述:

Command 'python3.7' not found, did you mean:

  command 'python3.8' from deb python3.8 (3.8.10-0ubuntu1~20.04)
  command 'python3.9' from deb python3.9 (3.9.5-3~20.04.1)
  command 'python2.7' from deb python2.7 (2.7.18-1~20.04.1)

确认没有安装两个并行安装的 Python 3.8,很明显 Linux 3.8.10 是 PostgreSQL 中 plpython3u 使用的版本。

plpython3u 存储过程测试与导入的包

我尝试了一个导入包的函数,取自Kmeans in PostgreSQL in a nutshell

CREATE OR replace FUNCTION kmeans(input_table text, columns text[], clus_num int) RETURNS bytea AS
 
$$
 
from pandas import DataFrame
from sklearn.cluster import KMeans
from pickle import dumps
 
all_columns = ",".join(columns)
if all_columns == "":
    all_columns = "*"
 
rv = plpy.execute('SELECT %s FROM %s;' % (all_columns, plpy.quote_ident(input_table)))
 
frame = []
 
for i in rv:
    frame.append(i)
df = DataFrame(frame).astype('float')
kmeans = KMeans(n_clusters=clus_num, random_state=0).fit(df._get_numeric_data())
return dumps(kmeans)
 
$$ LANGUAGE plpython3u;

输出:

CREATE FUNCTION

测试抛出错误:

postgres=# SELECT kmeans('my_table', ARRAY['col1', 'col2'],3);
ERROR:  ModuleNotFoundError: No module named 'pandas'
CONTEXT:  Traceback (most recent call last):
  PL/Python function "kmeans", line 3, in <module>
    from pandas import DataFrame
PL/Python function "kmeans"

然后,我在 Python 中安装了 pandas 3.8

python3.8 -m pip install pandas
Collecting pandas
  Downloading pandas-1.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.5 MB)
     |████████████████████████████████| 11.5 MB 6.0 MB/s
Collecting python-dateutil>=2.7.3
  Downloading python_dateutil-2.8.2-py2.py3-none-any.whl (247 kB)
     |████████████████████████████████| 247 kB 4.7 MB/s
Collecting numpy>=1.17.3
  Downloading numpy-1.21.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (15.8 MB)
     |████████████████████████████████| 15.8 MB 131 kB/s
Collecting pytz>=2017.3
  Downloading pytz-2021.1-py2.py3-none-any.whl (510 kB)
     |████████████████████████████████| 510 kB 5.7 MB/s
Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.7.3->pandas) (1.14.0)
Installing collected packages: python-dateutil, numpy, pytz, pandas
  WARNING: The scripts f2py, f2py3 and f2py3.8 are installed in '/home/my_user/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed numpy-1.21.2 pandas-1.3.2 python-dateutil-2.8.2 pytz-2021.1

熊猫现在存储在:

python3.8 -m pip show pandas
Name: pandas
Version: 1.3.2
Summary: Powerful data structures for data analysis, time series, and statistics
Home-page: https://pandas.pydata.org
Author: The Pandas Development Team
Author-email: pandas-dev@python.org
License: BSD-3-Clause
Location: /home/my_user/.local/lib/python3.8/site-packages
Requires: numpy, python-dateutil, pytz
Required-by:

但是测试仍然抛出同样的错误:

postgres=# SELECT kmeans('my_table', ARRAY['col1', 'col2'],3);
ERROR:  ModuleNotFoundError: No module named 'pandas'
CONTEXT:  Traceback (most recent call last):
  PL/Python function "kmeans", line 3, in <module>
    from pandas import DataFrame
PL/Python function "kmeans"

问题

如何安装 pandas(或我需要的任何其他包),以便 Linux 上的 PostgreSQL 13 plpython3u 扩展找到它?

PS:可能不需要旁注

可能不需要:在 plpython3u 存储过程中使用“which”来检查 Python

分拆的问题中有另一个版本测试,但没有显示扩展内部的任何内容,命令与普通 bash 中的命令相同。因此,下面的值被简化为只是一个plpython3u函数的随机测试。我添加这个只是因为你永远不应该 100% 确定。对我来说,很明显这并没有说明 plpython3u 实际使用的 Python 版本。

CREATE OR REPLACE FUNCTION get_py()
  RETURNS VARCHAR
AS $$
    import os
    return os.popen('which python3').read()
$$ LANGUAGE plpython3u;

输出:

CREATE FUNCTION

测试:

SELECT get_py();
      get_py
------------------
 /usr/bin/python3+

(1 row)

'which python3.8'也一样:

select get_py();
       get_py
--------------------
 /usr/bin/python3.8+

(1 row)

可能不需要:使用 make 和默认 Python 版本进行安装

也许在安装之前必须更改 Python 的默认版本?这只是来自an installation using make, with Python settings in /etc/make.conf 的一个非常模糊的猜测,这是那里使用的代码(2018 年的问题):

/etc/make.conf 更改为

DEFAULT_VERSIONS+= python=3.6

据说这个跑通安装了plpython3u(这个我没测试过):

root@db% cd /usr/ports/databases/posgresql10-plpython
root@db% make fetch
root@db% make extract
root@db% cd /usr/ports/databases/postgresql10-plpython/work/postgresql-10.5
root@db% ./configure PYTHON=/usr/local/bin/python3 --with-python --with-libraries=/usr/local/lib --with-includes=/usr/local/include/
root@db% cd /usr/ports/databases/posgresql10-plpython
root@db% make install

【问题讨论】:

  • 不清楚您是如何实际安装plpython3u 扩展的?另外,您是如何安装 Postgres 以及从哪个仓库安装的?你在使用任何类型的容器吗?我刚看到这个Location: /home/my_user/.local/lib/python3.8/site-packages。该软件包正在作为用户本地软件包安装,并且扩展正在寻找系统软件包,因为服务器正在作为系统服务运行。
  • @AdrianKlaver 我添加了安装步骤。如何将软件包安装为系统软件包?
  • 我原以为python3.8 -m pip install pandas 会安装到系统目录,因为我认为您需要使用--user 才能将其安装到您的主目录。我会运行python3.8 -m pip config list 来查看是否设置了配置变量。
  • @AdrianKlaver 也许这是因为我在 WSL2 上。 python3.8 -m pip config list 什么也不返回。哪条路径是正确的系统路径?会不会是/lib/python3.8/site-packages 而不是/home/my_user/.local/lib/python3.8/site-packages
  • sudopip 一起使用将安装到系统site-packages。对于像 plpython3u 这样的东西,在 Python 启动时并不是一件坏事,return sys.version 会在那里寻找。不推荐的建议来自开发工作,最佳实践是在 virtenv 中工作并安装到该位置或使用本地(家庭)软件包。然后,您不会添加/覆盖/删除操作系统或其他程序可能需要并且可能固定到特定版本的系统级包。

标签: python-3.x linux postgresql ubuntu


【解决方案1】:

问题在于:

python3.8 -m pip install pandas

在运行命令的用户主目录中的site-packages 中安装一个包(本例中为pandas),因此:

/home/my_user/.local/lib/python3.8/site-packages

在 Postgres 中运行的 plpython3u 扩展正在寻找系统范围内的包 site-packages。要在那里获取包裹,您需要执行以下操作:

sudo python3.8 -m pip install pandas

【讨论】:

  • 有效。甚至不需要重新启动 postgresql,psql 在运行时就可以看到已安装的包。还检查了:我不需要卸载.local 目录中不需要的包。我可以运行python3.8 -m pip uninstall pandas,但我不需要,因为无论如何psql只会搜索全局安装,而全局和本地安装没有链接。
  • 实际上是plpython3u 接了包裹。 psql 是 Postgres 客户端程序,不查找 Python 包。它现在可以工作了,因为 plpython3u 函数基本上是一个 Python 脚本,它在运行时是 import('s),所以一旦包在正确的位置,脚本就可以执行 import。是的,除非你弄乱了 PYTHONPATH 本地和全局应该保持分开。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多