從入門(mén)到精通:Python項(xiàng)目打包與setup.py實(shí)戰(zhàn)指南
1. 概述
在Python開(kāi)發(fā)中,我們經(jīng)常需要將自己的代碼打包成可供其他人使用的庫(kù)或應(yīng)用程序。為了方便用戶(hù)安裝和使用,我們需要?jiǎng)?chuàng)建一個(gè)配置文件 setup.py,用于定義打包的相關(guān)信息和依賴(lài)項(xiàng)。本文將詳細(xì)介紹如何編寫(xiě) setup.py 文件,并展示每一步需要做什么。
1.1 為什么需要對(duì)項(xiàng)目分發(fā)打包?
平常我們習(xí)慣了使用 pip 來(lái)安裝一些第三方模塊,這個(gè)安裝過(guò)程之所以簡(jiǎn)單,是因?yàn)槟K開(kāi)發(fā)者為我們默默地為我們做了所有繁雜的工作,而這個(gè)過(guò)程就是 打包。
打包,就是將你的源代碼進(jìn)一步封裝,并且將所有的項(xiàng)目部署工作都事先安排好,這樣使用者拿到后即裝即用,不用再操心如何部署的問(wèn)題(如果你不想對(duì)照著一堆部署文檔手工操作的話(huà))。
不管你是在工作中,還是業(yè)余準(zhǔn)備自己寫(xiě)一個(gè)可以上傳到 PyPI 的項(xiàng)目,你都要學(xué)會(huì)如何打包你的項(xiàng)目。
Python 發(fā)展了這么些年了,項(xiàng)目打包工具也已經(jīng)很成熟了。他們都有哪些呢?
你可能聽(tīng)過(guò) disutils、 distutils 、distutils2、setuptools等等,好像很熟悉,卻又很陌生,他們都是什么關(guān)系呢?
1.2 包分發(fā)的始祖:distutils
distutils 是 Python 的一個(gè)標(biāo)準(zhǔn)庫(kù),從命名上很容易看出它是一個(gè)分發(fā)(distribute)工具(utlis),它是 Python 官方開(kāi)發(fā)的一個(gè)分發(fā)打包工具,所有后續(xù)的打包工具,全部都是基于它進(jìn)行開(kāi)發(fā)的。
distutils 的精髓在于編寫(xiě) setup.py,它是模塊分發(fā)與安裝的指導(dǎo)文件。
那么如何編寫(xiě) setup.py 呢?這里面的內(nèi)容非常多,我會(huì)在后面進(jìn)行詳細(xì)的解析,請(qǐng)你耐心往下看。
你有可能沒(méi)寫(xiě)過(guò) setup.py ,但你絕對(duì)使用過(guò) setup.py 來(lái)做一些事情,比如下面這條命令,我們經(jīng)常用它來(lái)進(jìn)行模塊的安裝。
python setup.py install
這樣的安裝方法是通過(guò)源碼安裝,與之對(duì)應(yīng)的是通過(guò)二進(jìn)制軟件包的安裝,同樣我也會(huì)在后面進(jìn)行介紹。
1.3 分發(fā)工具升級(jí):setuptools
setuptools 是 distutils 增強(qiáng)版,不包括在標(biāo)準(zhǔn)庫(kù)中。其擴(kuò)展了很多功能,能夠幫助開(kāi)發(fā)者更好的創(chuàng)建和分發(fā) Python 包。大部分 Python 用戶(hù)都會(huì)使用更先進(jìn)的 setuptools 模塊。
distribute,或許你在其他地方也見(jiàn)過(guò)它,這里也提一下。
distribute 是 setuptools 有一個(gè)分支版本,分支的原因可能是有一部分開(kāi)發(fā)者認(rèn)為 setuptools 開(kāi)發(fā)太慢了。但現(xiàn)在,distribute 又合并回了 setuptools 中。因此,我們可以認(rèn)為它們是同一個(gè)東西。
還有一個(gè)大包分發(fā)工具是 distutils2,其試圖嘗試充分利用distutils,setuptools 和 distribute 并成為 Python 標(biāo)準(zhǔn)庫(kù)中的標(biāo)準(zhǔn)工具。但該計(jì)劃并沒(méi)有達(dá)到預(yù)期的目的,且已經(jīng)是一個(gè)廢棄的項(xiàng)目。
因此,setuptools 是一個(gè)優(yōu)秀的,可靠的 Python 包安裝與分發(fā)工具。
2. setup.py 文件的創(chuàng)建
首先,我們需要在項(xiàng)目的根目錄下創(chuàng)建一個(gè) setup.py 文件。這個(gè)文件將包含我們用于打包的配置信息。
3、詳解 setup.py 的編寫(xiě):
from setuptools import setup, find_packages
from pkg_resources import parse_requirements
with open("requirements.txt", encoding="utf-8") as fp:
install_requires = [str(requirement) for requirement in parse_requirements(fp)]
setup(
name="my_package",
version="1.0.0",
author="Your Name",
author_email="your_email@example.com",
description="A short description of your package",
long_description="eds sdk for python",
license="Apache License, Version 2.0",
url="http://test.com",
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
include_package_data=True, # 一般不需要
packages=find_packages(),
install_requires=install_requires,
entry_points={
'console_scripts': [
'test = test.help:main'
]
}3.1、基礎(chǔ)描述信息:
name: 包的名稱(chēng)
version: (-V) 包的版本號(hào)
author: 包的作者姓名
author_email: 作者的電子郵件地址
maintainer 維護(hù)者
maintainer_email 維護(hù)者的郵箱地址
description: 包的簡(jiǎn)要描述
long_description 程序的詳細(xì)描述
url: 包的項(xiàng)目主頁(yè)
platforms 程序適用的軟件平臺(tái)列表
3.1.1 程序分類(lèi)信息
classifiers: 用于指定所屬分類(lèi)的列表,例如所支持的Python版本、所使用的許可證等.所有支持的分類(lèi)列表見(jiàn):https://pypi.org/pypi?%3Aaction=list_classifiers
classifiers = [
# 發(fā)展時(shí)期,常見(jiàn)的如下
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
# 開(kāi)發(fā)的目標(biāo)用戶(hù)
'Intended Audience :: Developers',
# 屬于什么類(lèi)型
'Topic :: Software Development :: Build Tools',
# 許可證信息
'License :: OSI Approved :: MIT License',
# 目標(biāo) Python 版本
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
]3.2、包的進(jìn)階信息:
data_files:(如果沒(méi)有可以不寫(xiě))裝過(guò)程中,需要安裝的靜態(tài)文件,如配置文件、service文件、圖片等??????
data_files=[ ('', ['conf/*.conf']), ('/usr/lib/systemd/system/', ['bin/*.service']), ],?packages: (自動(dòng)搜索 Python 包)包含的模塊列表(包含__init__.py的文件夾),這里通常使用 find_packages(),它默認(rèn)在和setup.py同一目錄下搜索各個(gè)含有 __init__.py的包。 有些不想要進(jìn)行打包的文件可以排除
packages=find_packages(exclude=["dist.*", "dist", "tests.*", "tests"]),
我們指定 packages 后會(huì)自動(dòng)將指定的 package 下的源代碼進(jìn)行打包。但是有的時(shí)候會(huì)有很多 subpackage,這個(gè)時(shí)候 setuptools 提供了 find_packages 來(lái)找到所有的 subpackages。
install_requires:(自動(dòng)安裝依賴(lài))
install_requires = ["requests"]: 需要安裝的依賴(lài)包。我們可以首先生成 requirements.txt 文件,接著使用生成的文件生成需要的參數(shù)。關(guān)于生成 requirements.txt 文件,可以參考Python自動(dòng)生成requirements.txt文件。
這個(gè)參數(shù)是在 setup.py 文件中指定依賴(lài),然后在使用 setuptools 安裝應(yīng)用時(shí),依賴(lài)包的相應(yīng)版本就會(huì)被自動(dòng)安裝。但是通常情況下,手動(dòng)寫(xiě)依賴(lài)會(huì)比較麻煩,我們可以使用 pipreqs 首先自動(dòng)生成 requirement.txt 文件,接著讀取這部分文件即可。
關(guān)于 install_requires, 有以下五種常用的表示方法:
'argparse',只包含包名。這種形式只檢查包的存在性,不檢查版本。方便,但不利于控制風(fēng)險(xiǎn)。
'setuptools==38.2.4',指定版本。這種形式把風(fēng)險(xiǎn)降到了最低,確保了開(kāi)發(fā)、測(cè)試與部署的版本一致,不會(huì)出現(xiàn)意外。缺點(diǎn)是不利于更新,每次更新都需要改動(dòng)代碼。
'docutils >= 0.3',這是比較常用的形式。當(dāng)對(duì)某個(gè)庫(kù)比較信任時(shí),這種形式可以自動(dòng)保持版本為最新。
'Django >= 1.11, != 1.11.1, <= 2',這是比較復(fù)雜的形式。如這個(gè)例子,保證了Django的大版本在1.11和2之間,也即1.11.x;并且,排除了已知有問(wèn)題的版本1.11.1(僅舉例)。對(duì)于一些大型、復(fù)雜的庫(kù),這種形式是最合適的。
'requests[security, socks] >= 2.18.4',這是包含了額外的可選依賴(lài)的形式。正常安裝requests會(huì)自動(dòng)安裝它的install_requires中指定的依賴(lài),而不會(huì)安裝security和socks這兩組依賴(lài)。這兩組依賴(lài)是定義在它的extras_require中。這種形式,用在深度使用某些庫(kù)時(shí)。
include_package_data: 引入非 Python 文件。默認(rèn)情況下只會(huì)對(duì) Python 源碼進(jìn)行打包,但是如果我們想要將其他靜態(tài)文件,例如 css 文件,或是 qt 的一些 ui 文件打包進(jìn)去,就需要使用這個(gè)參數(shù)。后面會(huì)有詳細(xì)的介紹。
ext_modules
ext_modules參數(shù)用于構(gòu)建 C 和 C++ 擴(kuò)展擴(kuò)展包。其是 Extension 實(shí)例的列表,每一個(gè) Extension 實(shí)例描述了一個(gè)獨(dú)立的擴(kuò)展模塊,擴(kuò)展模塊可以設(shè)置擴(kuò)展包名,頭文件、源文件、鏈接庫(kù)及其路徑、宏定義和編輯參數(shù)等。如:
setup(
# other arguments here...
ext_modules=[
Extension('foo',
glob(path.join(here, 'src', '*.c')),
libraries = [ 'rt' ],
include_dirs=[numpy.get_include()])
]
)詳細(xì)了解可參考:2. Writing the Setup Script — Python 3.6.15 documentation
3.3、制作命令行工具:
entry_points: 動(dòng)態(tài)發(fā)現(xiàn)服務(wù)和插件,可以用來(lái)制作命令行工具。也就是我們可以通過(guò)一些簡(jiǎn)單的命令,來(lái)運(yùn)行 Python 項(xiàng)目中的指定文件或是函數(shù)。下面會(huì)詳細(xì)進(jìn)行介紹。
entry_points 的說(shuō)明
entry_points 可以用來(lái)創(chuàng)建控制臺(tái)腳本。我們看上面的例子就會(huì)非常好理解:
entry_points = {
'console_scripts': [
'test = test.help:main'
]
}這樣在安裝完畢之后,我們可以直接在控制臺(tái)輸入 test,這樣是可以運(yùn)行 test.help 模塊下的 main 函數(shù)。
4、執(zhí)行安裝文件
在有了上面的 setup.py 文件之后,我們就可以進(jìn)行打包,也可以將應(yīng)用安裝在本地的 Python 環(huán)境中了。一共有以下的四種安裝方式:
4.1、創(chuàng)建 egg 包
下面的命令會(huì)在當(dāng)前目錄下的 dist 目錄內(nèi)創(chuàng)建一個(gè) egg 文件。文件名格式就是 應(yīng)用名-版本號(hào)-Python版本.egg。同時(shí)你會(huì)注意到,當(dāng)前目錄多了 build 和 應(yīng)用名.egg-info 子目錄來(lái)存放打包的中間結(jié)果。(主要是看 dist 目錄下的內(nèi)容)
python setup.py bdist_egg
4.2、創(chuàng)建 tar.gz 包
這個(gè)命令和上例類(lèi)似,只不過(guò)創(chuàng)建的文件類(lèi)型是 tar.gz,文件名為 應(yīng)用名-版本號(hào).tar.gz。也是保存在 dist 文件夾下。
python setup.py sdist --formats=gztar
4.3、安裝應(yīng)用
下面的安裝命令會(huì)將當(dāng)前的 Python 應(yīng)用安裝到當(dāng)前 Python 環(huán)境的 site-packages 目錄下,這樣其他程序就可以像導(dǎo)入標(biāo)準(zhǔn)庫(kù)一樣導(dǎo)入該應(yīng)用的代碼了。
python setup.py install # 或者 pip install . # 暫時(shí)還沒(méi)有測(cè)試
這里我們?nèi)绻胍獎(jiǎng)h除安裝的包,可以使用 pip uninstall xxx 來(lái)完成刪除。
4.4、以開(kāi)發(fā)方式安裝
如果應(yīng)用在開(kāi)發(fā)過(guò)程中會(huì)頻繁變更,每次安裝還需要先將原來(lái)的版本卸掉,這樣就會(huì)很麻煩。如果使用 develop 開(kāi)發(fā)方式安裝的話(huà),應(yīng)用代碼不會(huì)真的被拷貝到本地 Python 環(huán)境的 site-packages 目錄下,而是在 site-packages 目錄里創(chuàng)建一個(gè)指向當(dāng)前應(yīng)用位置的鏈接。這樣如果當(dāng)前位置的源碼被改動(dòng),就會(huì)馬上反映到 site-packages 里。
python setup.py develop
或者也可以使用命令
pip install -e .
是 pip 命令的一種使用方式,它表示在當(dāng)前目錄下安裝一個(gè)可編輯包。具體含義如下:
- pip 是 Python 的軟件包管理器,用于安裝、卸載和管理 Python 包;
- install 是 pip 命令的一個(gè)子命令,用于安裝 Python 包;
- -e 表示使用可編輯模式安裝包,即把包安裝到當(dāng)前目錄,并且可以通過(guò)編輯包代碼實(shí)時(shí)調(diào)試;
- . 表示安裝當(dāng)前目錄下的包。
因此,pip install -e . 的含義是:在當(dāng)前目錄下安裝一個(gè)包,并創(chuàng)建一個(gè)軟連接引用該包(而不是將包復(fù)制到 site-packages 目錄下)。這個(gè)軟連接是一個(gè)指向包代碼的符號(hào)鏈接,它可以使包的修改直接反映到當(dāng)前目錄下的項(xiàng)目中,從而方便開(kāi)發(fā)和調(diào)試。
到此這篇關(guān)于從入門(mén)到精通:Python項(xiàng)目打包與setup.py實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Python項(xiàng)目打包與setup.py內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 實(shí)現(xiàn)二叉查找樹(shù)的示例代碼
這篇文章主要介紹了Python 實(shí)現(xiàn)二叉查找樹(shù)的示例代碼,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2020-12-12
Pytorch DataLoader 變長(zhǎng)數(shù)據(jù)處理方式
今天小編就為大家分享一篇Pytorch DataLoader 變長(zhǎng)數(shù)據(jù)處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01
使用python實(shí)現(xiàn)kNN分類(lèi)算法
這篇文章主要為大家詳細(xì)介紹了使用python實(shí)現(xiàn)kNN分類(lèi)算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
一行代碼解決動(dòng)態(tài)執(zhí)行Python函數(shù)方法實(shí)例
這篇文章主要為大家介紹了如何用一行代碼解決動(dòng)態(tài)執(zhí)行Python函數(shù)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
Pytorch 中net.train 和 net.eval的使用說(shuō)明
這篇文章主要介紹了Pytorch 中net.train 和 net.eval的使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05

