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:\Users\Mr.Bool\Desktop\testproject\testp

2.卸載

python3 -m pip uninstall C:\Users\Mr.Bool\Desktop\testproject\testp  

在系統包上卸載包是很危險的可能會卸掉某些重要文件,這也證明虛擬環境對於開發的重要性 3.開發模式下安裝

python3 -m pip install -e C:\Users\Mr.Bool\Desktop\testproject\testp

命名空間包

命名空間有兩種,一種是上下問的命名空間,即保存變量的字典稱為命名空間,有模塊的全局命名空間,函數方法的本地命名空間,內置名稱的命名空間
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程序的工具,兩個工具優先級比前兩個低,如果前兩個不好用,再用這兩個


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM