python打包与分发(setup模块)

本文详细介绍使用Python的setup.py脚本进行包构建、不同格式安装包制作、跨平台打包及发布流程。涵盖sdist、wheel、egg等安装包类型,以及在Windows、Linux上的具体操作,包括使用PyPI发布包的步骤。

 

setup模块命令查看:python setup.py --help-commands

C:\Users\******\Desktop\pyzo>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++ and Cython 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
  check             perform some checks on the package
  upload            upload binary package to PyPI

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

usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
   or: setup.py --help [cmd1 cmd2 ...]
   or: setup.py --help-commands
   or: setup.py cmd --help

命令分类总结:

1:源码安装包: 
    python3 setup.py sdist 
        tar.gz 或 zip 格式安装包, 安装方式: pip3 install 安装包

    python3 setup.py bdist_wheel
        whl安装包,安装方式: pip3 install 安装包

    python3 setup.py bdist_egg
        egg安装包, 安装方式:easy_install 安装包

2:创建window平台的二进制安装包:
    在window系统下执行命令打包, 
    安装后会有 ***.exe 的快捷方式, 双击即可启动

    python3 setup.py bdist 
        setup()函数中需要有entry_points参数
        zip安装包, 安装方式: 解压安装,解压后目录中有  ***.exe 文件, 双击即可运行。

    python3 setup.py bdist_wininst 
        安装方式:双击 ***.exe 安装包,按提示进行安装

3:创建linux平台的安装包:在linux系统下执行命令打包
    python3 setup.py bdist_dumb  

    python3 setup.py bdist_rpm  
        打包成rpm安装包, 可使用yum工具安装
        安装方式: yum install 安装包
4:创建wheel安装包
   python3 setup.py bdist_wheel
 
5:包的发布:register、upload
  
    PyPI(Python Package Index) 是 Python 官方维护的第三方包仓库,
    用于统一存储和管理开发者发布的 Python 包。

    如果要发布自己的包,需要先到 pypi 上注册账号。
    然后创建 ~/.pypirc 文件,此文件中配置 PyPI 访问地址和账号。
    如的.pypirc文件内容请根据自己的账号来修改。

    典型的 .pypirc 文件
        [distutils]
        index-servers = pypi

        [pypi]
        username:xxx
        password:xxx


    接着注册项目:
        python setup.py register
            该命令在 PyPi 上注册项目信息,成功注册之后,
            可以在 PyPi 上看到项目信息。最后构建源码包发布即可:

        python setup.py sdist upload


6:build_ext、build_clib暂时未知如何使用

7: setup打包成的pyd文件,就是python在window中的动态库
    setup打包成的so文件,就是python在linux中的动态库

8:通过通用--help选项找到特定命令支持的选项列表
    如:python setup.py --help build_ext

setup.py文件:

文件结构示例:

import os
import sys


# setup模块导入
try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup

# 定义一个函数,用于获取版本号 和 注释
def get_version_and_doc(filename):
    NS = dict(__version__='', __doc__='')
    docStatus = 0  # Not started, in progress, done
    for line in open(filename, 'rb').read().decode().splitlines():
        if line.startswith('__version__'):
            exec(line.strip(), NS, NS)
        elif line.startswith('"""'):
            if docStatus == 0:
                docStatus = 1
                line = line.lstrip('"')
            elif docStatus == 1:
                docStatus = 2
        if docStatus == 1:
            NS['__doc__'] += line.rstrip() + '\n'
    if not NS['__version__']:
        raise RuntimeError('Could not find __version__')
    return NS['__version__'], NS['__doc__']


# 收集项目中有__init__.py文件存在的所有目录,然后传给setup函数的packages参数,会自动收集所
# 有py文件
def package_tree(pkgroot):
    subdirs = [os.path.relpath(i[0], THIS_DIR).replace(os.path.sep, '.')
               for i in os.walk(os.path.join(THIS_DIR, pkgroot))
               if '__init__.py' in i[2]]
    return subdirs


# 收集项目中所有非py文件(数据文件、pyc文件等)
def get_unpy(path, li=[]):
    """获取所有非py文件"""
    li_path = os.listdir(path)
    if not li_path:
        return
    for i in li_path:
        file_path = os.path.join(path, i)
        if os.path.isdir(file_path):
            if file_path.endswith(".idea"):
                continue
            get_unpy(file_path, li)
        elif os.path.isfile(file_path):
            if i.endswith('.py'):
                continue
            the_file_path = os.path.relpath(os.path.abspath(file_path), THIS_DIR)
            li.append(the_file_path)
    return li



# 定义setup函数所需要的参数
THIS_DIR = os.path.dirname(__file__)
name = 'pyzo'
description = 'the Python IDE for scientific computing'
version, doc = get_version_and_doc(os.path.join(THIS_DIR, name, '__init__.py'))


# setup函数上面定义的, 不论是安装或打包, 都会先执行
# setup函数上面, 可以定义一些函数并使用下面这个条件进行限制,可以在安装这个安装包之前做一些操# 作, 如将之前的版本或数据进行备份
# if len(sys.argv) >= 2 and sys.argv[1] == "install":



# setup 函数
setup(
    name = name,
    version = version,
    author = 'Almar Klein',
    author_email = 'almar.klein@gmail.com',
    license = '(new) BSD',

    url = 'http://www.pyzo.org',
    keywords = "Python interactive IDE Qt science computing",
    description = description,
    long_description = doc,

    platforms = 'any',
    provides = ['pyzo'],
    install_requires = ['PyQt5'],  # and 'PySide' or 'PySide2' or 'PyQt5' or 'PyQt4'

    packages = package_tree(name),
    package_dir = {'pyzo': 'pyzo'},
    package_data = {'pyzo': ['license.txt', 'contributors.txt',
                            'resources/*.*',
                            'resources/icons/*.*',
                            'resources/appicons/*.*',
                            'resources/images/*.*',
                            'resources/fonts/*.*',
                            'resources/themes/*.*',
                            'resources/translations/*.*',
                             'resources/libs/mips64/*.*',
                             'resources/libs/x86_64/*.*',
                             'resources/libs/x86_64/old/*.*']},
    zip_safe = False,

    classifiers = [],

    entry_points = {'console_scripts': ['pyzo = pyzo.__main__:main',], },
    )


# setup函数下面定义的, 不论是安装或打包, 都会后执行
# setup函数下面, 可以定义一些函数并使用下面这个条件进行限制,可以在安装这个安装包之后做一些操# 作, 如对安装后的目录结构进行调整、添加环境变量等
# if len(sys.argv) >= 2 and sys.argv[1] == "install":

setup函数参数含义:

参数	                    说明
name	                    包名称
version	                    包版本
author	                    程序的作者
author_email	            程序的作者的邮箱地址
maintainer	                维护者
maintainer_email	        维护者的邮箱地址
url	                        程序的官网地址
license	                    程序的授权信息
description	                程序的简单描述
long_description	        程序的详细描述
platforms	                程序适用的软件平台列表
classifiers	                程序的所属分类列表
keywords	                程序的关键字列表
packages	                需要处理的包目录(通常为包含 __init__.py 的文件夹)
py_modules	                需要打包的 Python 单文件列表
download_url	            程序的下载地址
cmdclass	                添加自定义命令
package_data	            指定包内需要包含的数据文件
include_package_data	    自动包含包内所有受版本控制(cvs/svn/git)的数据文件
exclude_package_data	    当 include_package_data 为 True 时该选项用于排除部分文件
data_files	                打包时需要打包的数据文件,如图片,配置文件等
ext_modules	                指定扩展模块
scripts	                    指定可执行脚本,安装时脚本会被安装到系统 PATH 路径下
package_dir	                指定哪些目录下的文件被映射到哪个源码包
requires	                指定依赖的其他包
provides	                指定可以为哪些模块提供依赖
install_requires	        安装时需要安装的依赖包
entry_points	            动态发现服务和插件,下面详细讲
setup_requires	            指定运行 setup.py 文件本身所依赖的包
dependency_links	        指定依赖包的下载地址
extras_require	            当前包的高级/额外特性需要依赖的分发包
zip_safe	                不压缩包,而是以目录的形式安装


更多参数可见:https://setuptools.readthedocs.io/en/latest/setuptools.html

setup.cfg文件:

setup.cfg 文件用于提供 setup.py 的默认参数,详细的书写规则可参考:https://docs.python.org/3/distutils/configfile.html

例子:

# 指定文件安装目录
[install]
install_lib=/root/pyzoTool

setup.py文件完整示例:

# -*- coding: utf-8 -*-

""" Setup script for the Pyzo package.
"""


import os
import sys

try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup


def get_version_and_doc(filename):
    NS = dict(__version__='', __doc__='')
    docStatus = 0  # Not started, in progress, done
    for line in open(filename, 'rb').read().decode().splitlines():
        if line.startswith('__version__'):
            exec(line.strip(), NS, NS)
        elif line.startswith('"""'):
            if docStatus == 0:
                docStatus = 1
                line = line.lstrip('"')
            elif docStatus == 1:
                docStatus = 2
        if docStatus == 1:
            NS['__doc__'] += line.rstrip() + '\n'
    if not NS['__version__']:
        raise RuntimeError('Could not find __version__')
    return NS['__version__'], NS['__doc__']


def package_tree(pkgroot):
    subdirs = [os.path.relpath(i[0], THIS_DIR).replace(os.path.sep, '.')
               for i in os.walk(os.path.join(THIS_DIR, pkgroot))
               if '__init__.py' in i[2]]
    return subdirs


## Define info of this package

THIS_DIR = os.path.dirname(__file__)

name = 'pyzo'
description = 'the Python IDE for scientific computing'

version, doc = get_version_and_doc(os.path.join(THIS_DIR, name, '__init__.py'))


## Setup
setup(
    name = name,
    version = version,
    author = 'Almar Klein',
    author_email = 'almar.klein@gmail.com',
    license = '(new) BSD',

    url = 'http://www.pyzo.org',
    keywords = "Python interactive IDE Qt science computing",
    description = description,
    long_description = doc,

    platforms = 'any',
    provides = ['pyzo'],
    install_requires = [],  # and 'PySide' or 'PySide2' or 'PyQt5' or 'PyQt4'

    packages = package_tree(name),
    package_dir = {'pyzo': 'pyzo'},
    package_data = {'pyzo': ['license.txt', 'contributors.txt',
                            'resources/*.*',
                            'resources/icons/*.*',
                            'resources/appicons/*.*',
                            'resources/images/*.*',
                            'resources/fonts/*.*',
                            'resources/themes/*.*',
                            'resources/translations/*.*']},
    zip_safe = False,

    classifiers = [
          'Development Status :: 5 - Production/Stable',
          'Intended Audience :: Science/Research',
          'Intended Audience :: Education',
          'Intended Audience :: Developers',
          'Topic :: Scientific/Engineering',
          'Topic :: Software Development',
          'License :: OSI Approved :: BSD License',
          'Operating System :: MacOS :: MacOS X',
          'Operating System :: Microsoft :: Windows',
          'Operating System :: POSIX',
          'Programming Language :: Python :: 3',
          ],

    entry_points = {'console_scripts': ['pyzo = pyzo.__main__:main',], },
    )


## Post processing

# Install appdata.xml on Linux if we are installing in the system Python
if sys.platform.startswith('linux') and sys.prefix.startswith('/usr'):
    if len(sys.argv) >= 2 and sys.argv[1] == 'install':
        fname = 'pyzo.appdata.xml'
        filename1 = os.path.join(os.path.dirname(__file__), fname)
        filename2 = os.path.join('/usr/share/metainfo', fname)
        try:
            bb = open(filename1, 'rb').read()
            open(filename2, 'wb').write(bb)
        except PermissionError:
            pass  # No sudo, no need to warn
        except Exception as err:
            print('Could not install %s: %s' % (fname, str(err)))
        else:
            print('Installed %s' % fname)

 

参考:
http://blog.konghy.cn/2018/04/29/setup-dot-py/#setup-cfg
https://www.cnblogs.com/cposture/p/9029023.html#_lab2_4_4
 

setup模块打包练习:https://download.youkuaiyun.com/download/YPFeime/12166192

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值