欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python的setup问题

程序员文章站 2022-05-21 14:48:05
最近在研究检测里面如何调用python层的,首先就是setup这个文件,所以需要简单了解一下。 编写setup.py文件,获取帮助:Python setup.py --help-...

最近在研究检测里面如何调用python层的,首先就是setup这个文件,所以需要简单了解一下。

编写setup.py文件,获取帮助:Python setup.py --help-commands

Standard commands:
  build             build everything needed to install
  build_py          "build" pure Python modules (copy to build directory)
  build_ext         build C/C++ extensions (compile/link to build directory)
  build_clib        build C/C++ libraries used by Python extensions
  build_scripts     "build" scripts (copy and fixup #! line)
  clean             clean up temporary files from 'build' command
  install           install everything from build directory
  install_lib       install all Python modules (extensions and pure Python)
  install_headers   install C/C++ header files
  install_scripts   install scripts (Python or otherwise)
  install_data      install data files
  sdist             create a source distribution (tarball, zip file, etc.)
  register          register the distribution with the Python package index
  bdist             create a built (binary) distribution
  bdist_dumb        create a "dumb" built distribution
  bdist_rpm         create an RPM distribution
  bdist_wininst     create an executable installer for MS Windows
  upload            upload binary package to PyPI
  check             perform some checks on the package

Extra commands:
  rotate            delete older distributions, keeping N newest files
  develop           install package in 'development mode'
  setopt            set an option in setup.cfg or another config file
  saveopts          save supplied options to setup.cfg or other config file
  egg_info          create a distribution's .egg-info directory
  install_egg_info  Install an .egg-info directory for the package
  alias             define a shortcut to invoke one or more commands
  easy_install      Find/get/install Python packages
  bdist_egg         create an "egg" distribution
  test              run unit tests after in-place build

setup函数各参数详解:
>>python setup.py --help
--name 包名称
--version (-V) 包版本
--author 程序的作者
--author_email 程序的作者的邮箱地址
--maintainer 维护者
--maintainer_email 维护者的邮箱地址
--url 程序的官网地址
--license 程序的授权信息
--description 程序的简单描述
--long_description 程序的详细描述
--platforms 程序适用的软件平台列表
--classifiers 程序的所属分类列表
--keywords 程序的关键字列表
--packages 需要打包的目录列表
--py_modules 需要打包的python文件列表
--download_url 程序的下载地址
--cmdclass
--data_files 打包时需要打包的数据文件,如图片,配置文件等
--scripts 安装时需要执行的脚步列表

setup.py打包命令各参数详解:
>>python setup.py --help-commands
--python setup.py build # 仅编译不安装
--python setup.py install #安装到python安装目录的lib下
--python setup.py sdist #生成压缩包(zip/tar.gz)
--python setup.py bdist_wininst #生成NT平台安装包(.exe)
--python setup.py bdist_rpm #生成rpm包

或者直接"bdist 包格式",格式如下:

#python setup.py bdist --help-formats
--formats=rpm RPM distribution
--formats=gztar gzip'ed tar file
--formats=bztar bzip2'ed tar file
--formats=ztar compressed tar file
--formats=tar tar file
--formats=wininst Windows executable installer

--formats=zip ZIP file

如:

python setup.py bdist --formats=zip 等价于 python setup.py sdist

某翻译版的说明:

1、packages告诉Distutils需要处理那些包(包含__init__.py的文件夹)
2、package_dir告诉Distutils哪些目录下的文件被映射到哪个源码包,感觉好像是一个相对路径的定义。一个例子:package_dir = {'': 'lib'},表示以lib为主目录。
3、ext_modules是一个包含Extension实例的列表,Extension的定义也有一些参数。
4、ext_package定义extension的相对路径
5、requires定义依赖哪些模块
6、provides定义可以为哪些模块提供依赖
7、scripts指定python源码文件,可以从命令行执行。在安装时指定--install-script
8、package_data通常包含与包实现相关的一些数据文件或类似于readme的文件。
package_data = {'': ['*.txt'], 'mypkg': ['data/*.dat'],}表示包含所有目录下的txt文件和mypkg/data目录下的所有dat文件。
9、data_files指定其他的一些文件(如配置文件)
setup(...,
      data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
                  ('config', ['cfg/data.cfg']),
                  ('/etc/init.d', ['init-script'])]
     )
规定了哪些文件被安装到哪些目录中。如果目录名是相对路径,则是相对于sys.prefix或sys.exec_prefix的路径。如果没有提供模板,会被添加到MANIFEST文件中。
执行sdist命令时,默认会打包哪些东西呢?
    所有由py_modules或packages指定的源码文件
    所有由ext_modules或libraries指定的C源码文件
    由scripts指定的脚本文件
    类似于test/test*.py的文件
    README.txt或README,setup.py,setup.cfg
    所有package_data或data_files指定的文件
还有一种方式是写一个manifest template,名为MANIFEST.in,定义如何生成MANIFEST文件,内容就是需要包含在分发包中的文件。一个MANIFEST.in文件如下:
include *.txt
recursive-include examples *.txt *.py
prune examples/sample?/build

standard commands(标准命令)是distutils内建命令,而Extra commands(附加命令)是像setuptools这样的第三方包创建的。

简介:
1.sdist:用来创建一个源码包,在windows下为zip格式,Linux下为tag.gz格式 。
setup.py示例:
from setuptools import setup
setup(name='xxx',version='0.1.1')
打包命令:python setup.py sdist
distutils将浏览包的路径,查找包含在档案中的文件,包括:
1)所有py_modules、packages和scripts选项隐含的python源文件
2)所有在ext_modules选项中列出的C源文件
3)符合test/test*.py模式的文件
4)README、README.txt、setup.py和setup.cfg文件
如果需要包含更多文件,那么可以使用MANIFEST.in文件模版,示例如下:
include xx.txt
include yy/xx.txt
....
2.bdist_egg:用来创建一个二进制分发版本,经常用来替代基于bdist生成的模式
3.install:安装包到python中。另外,他还可能会安装在setup.py中的install_requires定义的

相关模块,例如:

install_requires=['...','...']

删除一个包:1)删除这个包所创建的文件,2)删除在site-packages文件夹easy-install.pth文

件中列举的所有引用。
4.develop:编译并且在适当的位置安装包,然后添加一个简单的链接到python site-packages文

件夹中,可以使用显式的-u选项删除包,例如:
python setup.py develop
python setup.py develop -u
使用该方式比其他方式安装包更好一些

5.创建一个新命令:这是由setuptools引入的,是一种将包定义为插件的简单方法,示例:
...entry_points='''
[distutils.commands]
my_command=my.command.module.Class
'''

6.打包时将其他类型的文件一起打包

distutils默认是不会打包py文件以外的文件的。

安装和了解distutils

python中自带了distutils,直接用

使用步骤 写一个安装脚本(setup.py)(可选)写一个安装配置文件创建一个源码分布(可选)创建一个或多个编译过的二进制分布 一个简单例子:
from distutils.core import setup
setup(name='test',
      version='1.0',
      py_modules=['test'],
      )

常见的python术语

module 组件 Python中可重用代码的基本单位,这里主要介绍纯python组件、扩展组件和包pure Python module 纯Python组件 完全由python写成的组件extension module 扩展组件 由低级语言(C,C++)等写成的组件package 包 一个含有别的组件的组件。通常包含在文件系统的目录下,并且显示声明在__init__.py文件中root package 根包。 在根目录sys.path下的包 distutils特有的包 module distribution 组件分布 一个可以安装的一系列组件的合集pure module distribution 纯组件分布non-pure module distribution 不纯组件分布,含有扩展组件distribution root 你的源码*的目录,即setup.py所在目录 安装脚本:
#!/usr/bin/env python

from distutils.core import setup

setup(name='test',
      version='1.0',
      description='test package',
      author='Su Yan',
      author_email='yansu0711@gmail.com',
      url='http://www.yansu.org',
      packages=['test'],
      scripts=['scripts/test.sh']
     )

这个例子包含了一些详细的信息,在packages中可以利用os.listdir(os.path.join('mydir','subdir'))等函数添加目录下全部目录。在packages中包含的目录中,最好有__init__.py来声明它是一个包,如果没有,会有异常提醒scripts这项指,如果你的包有执行文件,可以将其复制到/usr/local/bin下。

接下来看个详细python之模块distutils(打包工具)
# -*- coding: utf-8 -*-
#python 27
#xiaodeng
#python之模块distutils,打包工具
import distutils
#distutils包有2个目的:
1)distutils希望让最终用户觉得安装新模块、包和工具的过程一致而轻松
2)distutils希望让新模块、包和工具的开发者觉得创建这些容易安装的分发包很轻松
总得来说,distutils就是用来打包的模块.
#2、用distutils如何打包?
#http://blog.csdn.net/five3/article/details/7847551
#setup.py
import codecs
import os
import sys
'''打包的用的setup必须引入'''
from distutils.core import setup
def read(fname):
    '''
    定义read(),用来读取目录下的长描述
    我们一般将README文件中的内容读取出来叫做长描述,这个会在pypi中你的包的页面展现出来
    你也可以不用此办法,直接手动写内容
    pypi上支持.rst格式的文件,暂时不支持md格式;rst格式的文件在pypi上会自动转化为html形式显示在你的包的信息页面上
    '''
    return codecs.open(os.path.join(os.path.dirname(__file__),fname)).read()


#setup函数参数说明
#--------------------------------------------------------------------------#
NAME='MyTest'
'''名字:一般填写包的名字即可'''
PACKAGES=['MyTest']#需要打包的目录列表
'''包:放置模块的名字,list形式,可放置多个;告诉Distutils需要处理那些包(包含__init__.py的文件夹)'''
DESCRIPTION='my first package'
'''描述:关于这个包的基本描述'''
LONG_DESCRIPTION=read('README.rst')
'''查查看包的具体更加详细的说明'''
KEYWORDS='test python package keyword'
'''当前包的关键词,方便pypi分类'''
AUTHOR='xiaodeng' #作者
AUTHOR_EMAIL='drgs156@xxx.com'
URL='http://blog.sina.com.cn/u/3712558093'#项目地址,没有可写pypi上该包的地址
VERSION='1.0.1'
LICENSE='MIT'#授权方式
#这3项变量未添加到setup变量中,测试时可添加进入试试.
DOWNLOAD_URL='' #程序的下载地址
DATA_FILES=''#打包时需要打包的数据文件,如图片,配置文件等
SCRIPTS=''  #安装时需要执行的脚步列表
#构造setup
setup(
    name=NAME,
    version=VERSION,
    description=DESCRIPTION,
    long_description=LONG_DESCRIPTION,
    classifiers=[
        'License :: OSI Approved :: MIT License',
        'Programming Language ::Python',
        'Intended Audience :: Developers',
        'Operating System :: OS Independent',
        ],
    keywords=KEYWORDS,
    author=AUTHOR,
    author_email=AUTHOR_EMAIL,
    url=URL,
    license=LICENSE,
    packages=PACKAGES,
    include_package_data=True,
    zip_safe=True,
    py_modules=['test','test1','test2'],     #填写你的模块py文件,就是要打包的python文件列表
    )
'''
安装
>>> python setup.py sdist // 源码安装包
>>> python setup.py bdist_wininst //Windows 下使用
>>> python setup.py bdist_rpm //Linux 下使用
'''
由于最近网速很卡几乎点不开,所以有兴趣的可以一步步学习完。

[制作] (#make)
[整理项目] (#project)
先创建一个项目的文件夹
$ mkdir eds # eds 是我项目的名称,你随意修改成自己的即可
$ cd eds
在里面在创建一个 edssdk 的文件夹,这个文件夹的名称我故意创建的和上层目录不一样,以免误会,这个文件夹其实就是包名称了
$ mkdir edssdk # 这个文件夹就是包名称
$ cd edssdk
这个时候就是写代码的时候了,如果项目逻辑简单,你可以选择在文件夹里面只创建一个 __init__.py 文件,将所有的函数写到此文件里
当然如果项目复杂,你可以多创建几个文件,这里我繁中取简,只创建一个其他文件。
$ touch __init__.py # 这个文件作用就是给这个文件夹打成包
$ touch help.py # 这里是你的逻辑代码了,我就简单写了
我写了两个函数在 help.py 中

$ cat help.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#############################################
# File Name: help.py
# Author: xingming
# Mail: huoxingming@gmail.com
# Created Time:  2015-12-11 01:23:50 AM
#############################################
def sum(*values):
    s = 0
    for v in values:
        i = int(v)
        s = s + i
    print s

def output():
    print 'http://xiaoh.me'

[制作PyPI包] (#pypi)

现在项目逻辑已经完成,那么开始做 PyPI 的包了。

在 eds 文件夹中,创建 Egg 的配置文件 setup.py,并填写配置

$ cat setup.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#############################################
# File Name: setup.py
# Author: xingming
# Mail: huoxingming@gmail.com
# Created Time:  2015-12-11 01:25:34 AM
#############################################
from setuptools import setup, find_packages
setup(
    name = "edssdk",
    version = "0.0.1",
    keywords = ("pip", "datacanvas", "eds", "xiaoh"),
    description = "eds sdk",
    long_description = "eds sdk for python",
    license = "MIT Licence",

    url = "http://xiaoh.me",
    author = "xiaoh",
    author_email = "huoxingming@gmail.com",

    packages = find_packages(),
    include_package_data = True,
    platforms = "any",
    install_requires = []
)
当你的包很复杂的时候,势必会引用其他的包,你需要将你所有引用的包名称写到 install_requires 这个里面:
install_requires = ["requests"]
当然 setup 还有很多可以选择的项可以填,你可以 python setup.py –help 查看,也可以去看 文档
OK,看一下现在目录的结构:
$ tree
$ eds
$ ├── edssdk
$ │ ├── help.py
$ │ └── __init__.py
$ └── setup.py
这里面还需要说一下,setup 文件支持用配置文件来编写里面的参数
$ cat setup.cfg
[metadata]
name = edssdk
version = 0.1.1
zip_safe = False

description = eds sdk
author = xiaoh
author_email = huoxingming@gmail.com

license = MIT Licence
platforms = any

[files]
packages = find_packages()
更多的帮助信息你可以查看 这篇文档 [打包] (#package)
打包这一步我认为比较简单,目前比较流行的2中打包的方式:
$ python setup.py bdist_egg # 生成类似 edssdk-0.0.1-py2.7.egg,支持 easy_install
$ python setup.py sdist # 生成类似 edssdk-0.0.1.tar.gz,支持 pip
上面两条命令都会将文件生成到 dist 目录中
当然还有其他非主流格式或者其他选项,可以通过下面这个命令查看:
$ python setup.py --help-commands
[部署到PyPI] (#deploy)
[注册PyPI包] (#register)
我是直接在 SSH 下面进行操作的,你也可以通过 网页 来做,SSH 步骤:
$ python setup.py register
running register
running egg_info
writing dependency_links to eds_sdk.egg-info/dependency_links.txt
writing eds_sdk.egg-info/PKG-INFO
writing top-level names to eds_sdk.egg-info/top_level.txt
reading manifest file 'eds_sdk.egg-info/SOURCES.txt'
writing manifest file 'eds_sdk.egg-info/SOURCES.txt'
running check
We need to know who you are, so please choose either:
1. use your existing login,
2. register as a new user,
3. have the server generate a new password for you (and email it to you), or
4. quit
Your selection [default 1]:
Username: xingming
Password:
Registering edssdk to https://pypi.python.org/pypi
Server response (200): OK
I can store your PyPI login so future submissions will be faster.
(the login will be stored in /home/xingming/.pypirc)
Save your login (y/N)?y
关于 register 更详细的内容可以看 PackageIndex
[上传到PyPI] (#upload)
上传文件也是有 SSH 和 网页两种方法。
网页: 在浏览器登陆到 PyPI 点击 Your packages 中 Egg 的项目,然后选择某个版本的 files 即可看到上传界面。
下面这句话还是比较常用的,因为你的包以后更新的话,就不用再去注册了,直接使用下面的命令生成包并上传即可。
SSH:
$ python setup.py sdist upload
这个又是一堆的输出信息,我就不罗列了。
安装测试
用 pip 安装:
$ pip install edssdk
Downloading/unpacking edssdk
Downloading edssdk-0.0.1.tar.gz
Running setup.py (path:/home/huoxm/pyvirt/build/edssdk/setup.py) egg_info for package edssdk
Installing collected packages: edssdk
Running setup.py install for edssdk
测试:
$ python -c "from edssdk import help; help.sum(3,5);help.output();"
8
现在这个 sdk 大家都可以用到了
关于 upload 更详细的内容可以看 Uploading
Tips
setup.py 中调用当前目录的文件一定要加 MANIFEST.in 并将调用文件 include 进来

使用 python setup.py sdist 打包时,如果 setup.py 调用了当前目录中的文件(如README.rst):
$ long_description = open('README.rst').read()
一定要在增加 MANIFEST.in 文件并将调用文件 include 进来,否则将导致用户在 pip install 时报文件找不到的错误,示例:
$ cat MANIFEST.in
include README.rst
更详情的可以看 docs.python.org
项目逻辑内容如果直接在 ‘__init__.py’ 中完成的话,那么引用就可以更简便了。
CLI工具制作
CLI命令行工具介绍
CLI(command-line interface,命令行界面)是指可在用户提示符下键入可执行指令的界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。
就我直观的理解就是,这就是给程序员使用的,可以在终端即使装XX的美妙工具。
CLI制作
由于是 CLI 的命令行工具,所以程序一定要有一个入口的位置,所以我在 help.py 里面添加了 main 函数:
def main():
print 'this is main()'
print sys.argv[1:]
if __name__ == "__main__":
main()
这个 main 下面会在 setup.py 中用到,下面说一下 setup.py 的相关修改。

看英文文档真的是头大,所以后来干脆到 github 上面去找 CLI 的源码来看。发现每个 CLI 工具的 setup.py 中都会有 entry_points 这个节点。
entry_points = {
'console_scripts': [
'edssdk = edssdk.help:main'
]
}
完整的 setup.py 为:
from setuptools import setup, find_packages

setup(
    name = "edssdk",
    version = "0.1.2",
    keywords = ("pip", "datacanvas", "eds", "xiaoh"),
    description = "eds sdk",
    long_description = "eds sdk for python",
    license = "MIT Licence",

    url = "http://xxx.xxx示例",
    author = "xiaoh",
    author_email = "huoxingming@gmail.com",

    packages = find_packages(),
    include_package_data = True,
    platforms = "any",
    install_requires = [],

    scripts = [],
    entry_points = {
        'console_scripts': [
            'edssdk = edssdk.help:main'
        ]
    }
)
这个里面多了一个 entry_points 节点,里面的 console_scripts 指明了命令行工具的名称:
edssdk = edssdk.help:main
等号前面指明了工具包的名称,等号后面的内容指明了程序的入口地址,当然,这个可以有多条记录,这样一个项目就可以制作多个命令行工具了
制作PyPI
制作包的过程和上面的是一样的
$ python setup.py sdist
$ python setup.py register
$ python setup.py sdist upload
安装测试

通过 pip 更新一下包:
$ pip install -U edssdk
测试工具包:
$ edssdk 2345
this is main()
['2345']
OK,方法已经找到了,CLI 工具也就好弄了。
setup.py
这里讲解一下 Setup.py 中的一些参数
packages 告诉Distutils需要处理那些包(包含__init__.py的文件夹)
package_dir 告诉Distutils哪些目录下的文件被映射到哪个源码包,感觉好像是一个相对路径的定义。一个例子:package_dir = {'': 'lib'},表示以lib为主目录。
ext_modules 是一个包含Extension实例的列表,Extension的定义也有一些参数。
ext_package 定义extension的相对路径
requires 定义依赖哪些模块
provides 定义可以为哪些模块提供依赖
scripts 指定python源码文件,可以从命令行执行。在安装时指定–install-script

package_data 通常包含与包实现相关的一些数据文件或类似于readme的文件。

package_data = {‘’: [‘.txt’], ‘mypkg’: [‘data/.dat’],}

表示包含所有目录下的txt文件和mypkg/data目录下的所有dat文件。

data_files 指定其他的一些文件(如配置文件)
setup(…,
data_files=[(‘bitmaps’, [‘bm/b1.gif’, ‘bm/b2.gif’]),
(‘config’, [‘cfg/data.cfg’]),
(‘/etc/init.d’, [‘init-script’])]
)
规定了哪些文件被安装到哪些目录中。如果目录名是相对路径,则是相对于 sys.prefix 或 sys.exec_prefix 的路径。如果没有提供模板,会被添加到MANIFEST文件中。
执行sdist命令时,默认会打包哪些东西呢?
所有由py_modules或packages指定的源码文件
所有由ext_modules或libraries指定的C源码文件
由scripts指定的脚本文件
类似于test/test*.py的文件
README.txt或README,setup.py,setup.cfg
所有package_data或data_files指定的文件
还有一种方式是写一个manifest template,名为MANIFEST.in,定义如何生成MANIFEST文件,内容就是需要包含在分发包中的文件。一个MANIFEST.in文件如下:
include *.txt
recursive-include examples *.txt *.py
prune examples/sample?/build
记FCON模块的pypi打包过程
fcon 是刚刚完成的一个python模块,他可以查找指定目录下的符合一定规则文件名的内容中包含一定规则的行,并打印出来。说起来比较拗口,就是三个参数,文件目录,文件正则,字符正则,三个一综合就是输出结果了。
这个工具主要帮我解决查找部分内容的功能,写的博客里面有好多用的是默认的背景图,有时间的时候我就会换一下,这时候我就需要查出来那些用到了默认的。
你可以通过 pip install fcon 来安装使用。
这次打包过程还挺烦的,一直有问题,是因为我用到了 Click模块 之后就发现,我不用指定内置的运行函数(main)了,而且,我希望可以输出version,并且这个version在setup.py里面也可以使用,这就高出了好多问题。还好刚刚都解决了。

首先说,看一下我所有文件的结构:
$ tree
.
├── bin
│ └── fcon
├── fcon
│ └── __init__.py
├── README.md
└── setup.py
2 directories, 4 files
可以发现,我的 fcon 脚本放到了 bin 目录下,而 fcon 文件夹里面只有一个 __init__.py 文件,这是为了包含的时候不冲突,比如我在 fcon 脚本里面用到了这句话:
try:
    import fcon
except:
    sys.path.append(os.path.join(os.path.dirname(__file__), "../"))
    import fcon

def output_version(ctx, param, value):
    if not value or ctx.resilient_parsing:
        return
    click.echo("Version: %s" % fcon.__version__)
    ctx.exit()
这个就是通过引用来设置 version 的部分,这样就实现了,version一处改,大家起开怀的要求了。__init__.py 如下:

__version__ = '0.0.17'
对的,就这么一句话。
再看我的 setup.py 关键就是这个文件了:
$ cat setup.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-

#############################################
# File Name: setup.py
# Author: xiaoh
# Mail: p.mars@163.com
# Created Time:  2015-12-11 01:25:34 AM
#############################################

from setuptools import setup, find_packages
import fcon

setup(
    name = "fcon",
    version = fcon.__version__,
    keywords = ("find", "fcon", "xiaoh"),
    description = "find content",
    long_description = "print files which contain the content you want to search.",
    license = "MIT Licence",

    url = "http://xiaoh.me",
    author = "xiaoh",
    author_email = "xiaoh@about.me",

    packages = ['fcon'],
    package_data = {
    },
    include_package_data = True,
    platforms = "any",
    install_requires = ["click"],

    scripts = ['bin/fcon']
#    entry_points = {
#        'console_scripts': [
#            'fcon = bin/fcon'
#        ]
#    }
)

就说这么多,关键还得是看脚本,看写法。一些练习的例子:地址,又扯远了,回归主题。

pva-faster-rcnn的lib目录下Makefile文件:

all:
	python setup.py build_ext --inplace
	rm -rf build

就是忽略build-lib路径(扩展模块)并将编译好的扩展模块同时与python的原模块放进source路径。这句话大概就是这个意思,然后你编译makefile文件时可以先去掉删除命令,看看里面时什么东西。