pyenv下python依赖的路径和打包项目

Python018

pyenv下python依赖的路径和打包项目,第1张

一个很好用的打包工具:pyinstaller

很简单,cd到目标项目的.py目录下,运行 pyinstaller -F file.py -F:表示只生成一个可执行文件,如果不加则会在dist文件夹下生成很多文件和一个可执行文件。

successfully之后,当前目录下会生成两个文件夹,一个dist,一个build,我们所需要的文件在dist里面。

直接运行就可以了

为啥不用这个方法呢,因为在python的包中,有的完全是python的, 而有的并不是纯python的 ,那么接下来介绍方法二,如何安全的提取打包。

我是从pycharm中找到了蛛丝马迹

现在全都找到了,如果你可以打开.py文件,那么路径更好找,直接cd过去就ok了:

回到之前我们的疑问: 怎么判断安装包是不是纯python的呢?

这里面的.so文件就不是python的文件,.py/.pyc是。所以这种包无法打包,只能到目标环境下手动安装。

找到我们需要的包,cp出去放到 sys.path 可以找到的路径下就可以了(放到你要run的那个文件夹里),结果如下:

重新创建一个虚拟环境,运行下export.py查看能否正常运行就ok了。

使用python内部基础工具包Distutils打包程序:

在打包之前需要做的就是配置好安装脚本,一般为setup.py文件;

示例(setup.py):

from distutils.core import setup

setup(name='Hello',

 version='1.0',

 description='example',

 author='haomiao',

 py_modules=['hello'])

该配置文件,只使用了py_modules参数,单一的模块文件名hello.py,当然还有其他的属性、选项可设置hello.py应与setup.py在同一目录下,分发的时候最好将该目录作为单独的一个目录文件,并将其所依赖的或需要的文件、资源均放在这个目录下或其子目录下,该目录就可以分发给其他开发人员或客户(一般的最终客户不会做这些安装的繁琐事情)

此外,若有其他的资源文件或是其他的多个py文件,则可以增加packages等其他相关的参数指令。

将该目录模块安装到python中;执行:python setup.py install ,此后将会复制相关文件至python安装路径下的Lib/site-packages下,

如上示例将会在该路径下产生:hello.py hello.pyc Hell-1.0-pyx.x.egg-info文件;在使用的时候直接:import hello即可使用。

在上述情况的基础上打包,再使用sdist命令(用于源码发布的形式)

执行:python setup.py sdist ,将产生两个目录build、dist以及MANIFEST列表文件,build下为中间文件可不用,dist下会打包成一个压缩文件,如:Hello-1.0.zip;事实上,该压缩文件内部包含之前的文件以及PKG-INFO的描述文件,这个时候该压缩文件就可以分发给用户;

可以的,虽然说pip比较流行,但rpm从原理上完全可以覆盖这些部署过程,只有一些小的要求:

所有环境的Python安装方式必须一致,不能存在某些Python是2.6,某些是2.7,某些装在/usr/local下面,某些在/usr/lib下面之类的情况

如果带有C扩展的话,链接到的库应当是来自某个rpm包的。如果没有的话就简单多了。

如果有依赖的其他Python包的话,需要把依赖的包也做成rpm;实在偷懒也可以打进同一个rpm中。

实际上发行版中有许多Python库都以rpm的形式提供,不过一般我们嫌它版本旧,更倾向于用pip管理一组新的。

要写一个rpm spec,可以从头自己写,也可以参考一些其他软件的spec,我建议你采用后者,既然你们公司已经广泛使用rpm了,那肯定有很多本公司的spec可以参考,也有人可以问。

回到话题,写rpm spec,或者说rpmbuild的过程,分成以下步骤:

部署源代码,一般来说将一个.tar.gz复制到SRC目录中,然后用%setup宏就可以了,这个宏也基本上没干什么特别的事,就是把.tar.gz解压缩了一下,然后进入相应目录。.tar.gz只要从git中取出干净的源代码,整个目录打成tar包就可以了。好像还有专门的git-archive命令。

build过程,对应C/C++项目中的./configure, make。对Python项目来说一般可以跳过,因为setup.py都会搞定。也可以选择在这个阶段使用setup.py进行build,build出一个wheel包来,这是我推荐的方法,因为wheel包和直接setup.py install的目录结构有一些差异,而pip安装默认是按照wheel的方式。也就是说在这一步调用:setup.py bdist_wheel。再精细一点可以指定build的目标为build目录,这样需要cleanup的时候容易一些。

install过程,对应C/C++项目中的make install。一般来说我们平时怎么装这个软件,这一步就怎么装,所以我们也是使用setup.py。唯一的技巧在于,我们需要指定安装的目标到rpmbuild根的某个目录下面,而不是系统的目录。这个目录在install开始之前应当被清空。可以参考其他spec。对于我们来说,就是将Python的库安装到指定的目录,而不是系统的site-packges当中。如果你在build这一步已经打包了wheel,那么使用wheel install命令、指定目标文件夹就可以了。

打包过程,rpm的打包原理非常简单,最开始install的目录是空的,install完成后里面有了一堆文件,那么就按照文件列表将这一堆文件打包、然后指定每个文件将来应当安装到什么位置。对于Python项目来说,一般会安装package名的目录和EGGINFO两个目录,将这两个目录连同里面所有的内容一起加入%files段就可以了。如果你要部署的是某个应用,一般你还会希望将init.d中的启动脚本、或者 systemd的配置文件以及其他应用的配置文件一起部署了,可以在install的过程中将这些文件从源文件目录中复制到目标文件夹里,然后加到files段里面。

安装、卸载脚本。表现为%pre, %post之类的段一般来说如果你有服务要安装的话,需要在这里使用chkconfig, chkconfig on,或者systemd的话就是systemctl enable。如果你希望安装完有个机会修改配置文件,可以选择在首次安装的时候不要启动服务,而在update的时候启动服务,这可以通过脚本传进的第一个命令行参数$1进行判断,0、1、2表示不同的情况(分别是卸载、安装、更新,具体的记不清了),可以参考其他人写的spec;也可以选择安装完永远直接启动,在post中使用service xxx start, 在preuninstall的时候使用service xxx stop。

rpm的功能还是很强大的,除了跟pip共通的功能以外,它有一个显著的好处就是可以帮助你同时管理服务的配置、启动和停止,从而简化部署过程。不过要注意如果使用rpm的话就不要同时使用pip,否则pip更新过的库,rpm卸载或更新时会冲突。

有第三方依赖的时候,一种方法是为每个依赖项写一个独立的spec,里面内容都是上面这样的直接调用setup.py,或者更简单一些,在install的时候直接调用pip就可以;然后在需要这些依赖项的rpm包的spec当中写上Require信息,跟pip体系的requirements差不多。偷懒也可以在同一个rpm中打了一堆Python包进去,但是如果有多个独立安装的rpm都打了同一个Python包,就会冲突,要注意。

其实用习惯了会觉得也不比pip差,需要跟非Python组件混合部署的时候反而会觉得简单了很多。