• python打包


    python打包

    python打包

    python打包有一个组织叫python packaging authority(pypa).还有一个python第三方仓库叫Python Package Index(Pypi) 与包有关的两种工具,一种是安装包的工具,另一种工具用于包的创建和分发

    安装包的工具

    1. pip安装来自PyPI的包
    2. virtualenv或venv用于python环境的应用隔离

    包的创建与分发

    1. 使用setuptools来定义项目并创建源代码发行版
    2. 使用wheel来创建构建发行版
    3. 使用twine像PyPI上传包

    打包上传需要的操作工具

    • 使用setuptools来创建项目源代码发行商
    • 使用wheel进行构建发行版,也就是打包
    • 使用twine像pypi仓库上传包的发行版

    项目配置

    创建大型的应用最简单的做法是分几个包,这样就像分成各个组件,这样易于理解维护和修改。
    1. setup.py
    一个需要上传入pypi的包来说,其应用根目录需要包含一个setup.py脚本。setup文件要包含可以被distutils打包工具可以解析的所有数据,使用setup()函数来传入元数据。distutils是一个标准模块,建议使用setuptools包来替换distutils,因为setuptools做了一些改进
    setup文件的最少内容情况

    from setuptools import setup  
    setup(
    name='wjtestpack'
    )

    setup中name的参数为要打包的全名,setup脚本可以使用一些命令,使用如下命令查看

    python3 setup.py --help-commands  
    #输出结果
    Standard commands:#标准命令 是distutils的内置命令
    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
    check perform some checks on the package
    upload upload binary package to PyPI

    Extra commands:setuptools包中定义的命令
    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'
    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

    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

    setup.cfg

    setup.cfg文件就是包含setup脚本命令的默认参数数据。如果创建包的过程复杂,需要像setup脚本传入参数很多,使用这个文件就简单很多。可以讲项目的默认参数保存在这个文件中。也将包的构建过程透明化。
    cfg文件与configparser语法相同,都是一个个节点与值对应

    [global]
    quiet=1
    [sdist]
    formats=zip,tar
    [bdist_wheel]
    universal=1

    以上配置描述的是,发行包创建格式为zip和tar两种格式的文件,并且构建wheel打包,全局命令quiet为1,所以命令的大部分输出被阻止。

    manifest.in

    mainifest文件就是一个包含发行包的所有文件的信息的文件,使用sdist命令构建包的时候,distutils会自动浏览应用中的所有文件,生成列表,保存在manifest文件中

    打包需要的元数据

    除了需要的包名和版本之外,setup函数可以接受很多参数
    * description:描述包的信息 * longdescription:完整包的说明,可以使用reStructuredText格式
    * keywords:包中关键字列表
    * author:作者的名称
    * author
    email:作者邮箱
    * url:项目URL * license:许可证
    * packages:包中所有名称的列表,setuptools有一个findpackages的函数计算
    * namespace
    packages:命令空间包的列表

    分发器trove

    分类器的主要作用是对你创建的包在pypi中有一个所属类的定位,分类器都是字符串形式,用::字符串分割每个命名空间。分类器列表在包的setup()函数中定义用的参数为classifiers,举个例子

    from setuptools import setup
    setup(
    name='mytestpack'
    classifiers=[
    'Development Status:: 4-Beta',
    'Intended Audience::Developers',
    'License::OSI...',
    'Operating System::OS',....
    ] )

    pypi分类器一共有9大类
    * 开发状态(Development Status) * 环境(Environment) * 框架(Framework) * 目标受众(Intended Audience) * 许可证(License) * 自然语言(Natural Language) * 操作系统(Operating System) * 编程语言(Programming Language) * 话题(Topic)

    常见模式

    其实打包信息可以在setup函数中接受大多数元数据的手动输入,代码如下

    from setuptools import setup
    setup(
    name='mytestpack'
    version='0.0.1',
    description='test package',
    long_description='wj first use setuptools',
    install_requires=[
    'dependency1',
    'dependenct2',
    ]
    )

    但是setuptools和distutils都不能从项目源代码中自动提取元数据信息,需要你自己提供这些信息。长远来看上面的方法很难维护。所以python社区有一些方法来解决这些问题:
    (1) 自动添加包的版本字符串
    这个操作需要将包的版本信息编写进包的init.py文件中,所以以后创建包的init.py文件需要包含如下格式的信息

    VERSION=(0,1,1)
    __version__='.'.join([str(x) for x in VERSION])  
    

    版本信息包含在VERSION和version中,这样访问这两个变量就可以获取版本号,所以在setup.py脚本中动态获取版本号代码如下

    from setuptools import setup  
    import os
    def get_version(version_tuple):
    if not isinstance(version_tuple[-1],int):
    return '.'.join(map(str,version_tuple[:-1]))+version_tuple[-1]
    return '.'.join(map(str,version_tuple))
    init=os.path.join(os.path.dirname(__file__),'下一层文件夹命',...,'__init__.py')
    version_line=list(
    filter(lambda l:l.startswith("VERSION"),open(init))
    )[0]
    VERSION=get_version(eval(version_line.split('=')[-1]))
    setup(
    name='mytestpack',
    version=VERSION,
    )

    (2)使用README文件
    python包在pypi中会显示一个项目的readme文件,pypi只支持reStructuredText标记语言。当然如果想使用其他语言,那就只能读取文件,然后将数据赋值到long_description中,这样也可以显示。这时需要使用pypandoc包将其他语言转换为reStructuredText

    try:  
    from pypandoc import convert
    def read_md(f):
    return convert(f,'rst')
    except ImportError:
    covert=None
    print('warning:pypandoc not found')
    README=os.path.join(os.path.dirname(__file__),'README.md')
    setup(
    name='mytestpack',
    long_description=read_md(README),
    )

    (3)管理依赖
    有些应用包的需要依赖其他包,这就要我们列出一个依赖列表,如下是一个明确表述依赖列表的形式:

    from setuptools import setup
    setup(
    name='mytestpack',
    install_requires=['pack1','pack2','pack3'],
    )

    也可以使用读取requirements.txt文件的形式

    from setuptools import setup  
    import os
    def strip_comments(l):
    reeturn l.split('#',1)[0].strip()
    def reqs(*f):
    return list(filter(None,[strip_comments(l) for l in open(os.path.join(os.getcwd(),*f)).readlines()]))
    setup(
    name='mytestpack',
    install_requires=reqs('requirements.txt')
    )

    自定义包命令

    distutils提供了自定义命令的入口点(entry point),只要在setup函数里使用entry_point参数就可以注册命令,这样的形式和crf文件格式类似

    setup(
    name='mytestpack',
    entry_point="""
    [distutils.commands]
    my_command=my.command.module.Class
    """,
    )

    开发期间使用包

    开发期间使用包就是为了测试包是否能正藏安装
    1.安装
    使用pip命令就可以将安装包注册到python树中,因为我的电脑里有两个版本的python,所以python的pip命令如下

    python3 -m pip install C:UsersMr.BoolDesktop	estproject	estp
    

    2.卸载

    python3 -m pip uninstall C:UsersMr.BoolDesktop	estproject	estp  
    

    在系统包上卸载包是很危险的可能会卸掉某些重要文件,这也证明虚拟环境对于开发的重要性 3.开发模式下安装

    python3 -m pip install -e C:UsersMr.BoolDesktop	estproject	estp

    命名空间包

    命名空间有两种,一种是上下问的命名空间,即保存变量的字典称为命名空间,有模块的全局命名空间,函数方法的本地命名空间,内置名称的命名空间
    1. 内置命名空间在 Python 解释器启动时创建,会一直保留,不被删除。
    2. 模块的全局命名空间在模块定义被读入时创建,通常模块命名空间也会一直保存到解释器退出。
    3. 当函数被调用时创建一个局部命名空间,当函数返回结果 或 抛出异常时,被删除。每一个递归调用的函数都拥有自己的命名空间。
    还有另外一种命名空间,叫做命名空间包,这是在项目中对于打包的时候用的一种功能。

    作用

    当你在开发应用是通常是多个组件,举个例子是当你的一个大的应用a中,包含b,c两个模块,而b和c是单独存在的两个模块,你可以单独使用,在没有命名空间包的情况下这是不可能的情况,因为b和c都在a的下面,要下载就只能都下载,出现了命名空间包,那么将a变成命名空间包,那么就在python的层面上将b,c可以单独使用和修改。但两个包又可以同时存在a的下面。

    pip install a.b
    pip install a.c

    而没有命名空间包的时候你要下载通用包

    pip install a

    使用

    隐式命名空间包

    隐式命名空间包意思就是只要在你写的应用中,不包含init.py的包就作为命名空间包,setup.py脚本中这样写:

    from setuptools import setup
    setup(
    name='a.b',
    packages=['a.b'],
    )

    古老的命名空间包

    古老的方法在a中是有文件init.py文件的,但必须是空白,但最好添加一段代码

    __import__('pkg_resources').declare_namespace(__name__)  
    

    在setup文件中这样声明

    from setuptools import setup
    setup(
    name='a.b',
    packages=['a.b],
    namespace_packages=['a'],#主动声明命名空间包
    )

    上传一个包

    python包仓库

    从pypi上下载python包不需要账号,只需要一个包管理器。首选是pip

    上传到pypi或其他仓库

    任何人都可以上传python包,只需要注册仓库的账户密码,包与账户绑定。上传一个包的简单方法使用setup.py的命令upload

    python setup.py 命令列表 upload  

    如果你想同事构建源代码发行版、构建发行版和wheel包,使用如下命令

    python setup.py sdist bdist bdist_wheel upload  
    

    因为这样作不安全,最好使用twine工具,可以在pypi平台下载,

    pytho setup.py sdist bdist_wheel  
    twine upload dist/*
    

    如果这个包没有注册上传会失败,先注册

    python register dist/*  
    

    .pypirc

    .pypirc是一个配置文件,保存python包仓库的信息

    [distutils]
    index-servers=pypi other #注册的仓库
    [pypi]
    repository:<仓库url>
    username:用户名
    password:密码
    [other]
    repository:<仓库url>
    username:用户名
    password:密码

    用户名密码可以空着,安全,必要时程序会提示输入

    源代码包与构建包

    1.sdist
    sdist命令创建源代码发行版

    python setup.py sdist  
    

    生成的文件形式为举例:mypackage-0.1.1.tar.gz的打包文件包含与项目相同的结构
    2.bdist和wheels
    分发预构建的发行版

    python setup.py bdist  
    

    会生成文件形式为wjtestpack-0.0.0.win-amd64.zip格式的压缩包,这个包里主要有site-packages的文件夹,和一些缓存字节码.pyc结尾的文件。
    使用wheels命令如下

    python setup.py bdist_wheel  
    

    生成的文件为wjtestpack-0.0.0-py3-none-any.whl形式的文件。

    独立可执行文件

    创建独立可执行文件是每种语言必须实现的,因为不会所有使用者都是程序员,也不会所有使用应用的电脑都有特定语言的解释环境。

    可执行文件的编译工具

    PyInstaller(首选工具)

    可以应用到多平台,不支持跨平台构建,使用pyinstaller首先需要用pip安装pyinstaller,使用pyinstaller创建独立可执行文件的命令如下

    pyinstaller 路径/mytest.py  
    

    这样运行会生成一个.spec文件和一个dist文件夹,文件夹中包含,许多文件,其中有一个exe可执行文件,当将应用发给用户时必须将整个文件夹发给用户。也可以使用如下命令

    pyinstaller --onefile mytest.py  
    

    使用--onefile构建可以去掉所有多余文件,在一会有.spec文件和dist文件夹下一个.exe可执行文件。
    .spec是一个配置文件,其实使用配置文件也可以生成可执行文件,命令如下,前提必须现有.spec文件,可以自己编写

    pyinstaller mytest.spec
    

    cx_Freeze

    也是可应用到多平台,不支持跨平台构建,这个工具的缺点为不能只生成可执行文件,它必须生成多个dll等关联文件。生成可执行文件命令为

    cxfreeze mytest.py  
    

    cxfreeze扩展了distutils包,可以直接使用setup.py文件配置构建生成可执行文件,setup.py代码如下

    import sys  
    from cx_Freeze import setup,Executable
    setup(
    name='mytest',
    version='0.0.1',
    description='使用cxfreeze',
    options={
    'build_exe':build_exe_options
    },
    executables=[Executable('mytest.py')]
    )

    执行命令为

    python setup.py build_exe  

    py2exe和py2app

    py2exe为生成windows程序的工具,py2app为生成mac程序的工具,两个工具优先级比前两个低,如果前两个不好用,再用这两个

  • 相关阅读:
    配置Echarts大全
    MAthJax入门教程(五分钟上手)
    JQ常用方法(哈哈)
    神奇的数组去重。
    echarts零基础快速入门
    css3 媒体查询的学习。
    css样式 body的font-size 为什么用625%
    移动端横向滚动条。
    剧中自适应问题
    iPhone 横屏时默认会放大文字的问题
  • 原文地址:https://www.cnblogs.com/dcotorbool/p/8278976.html
Copyright © 2020-2023  润新知