python項目的結構和包的建立
在python的圈子裡,有許多人無償得公開自己開發的程式庫,使用者可以通過pip 指令來安裝這些庫,我們在釋出時需要将其建立成一種特殊的檔案,這種檔案就是程式包,我們将會在本節學到程式包的制作流程:
- python項目目錄結構以及檔案結構
- 對第二章學習的留言闆應用進行整理,封裝成包
- 最後學習如何将我們開發的項目釋出在PyPI上,與全世界的人分享
3.1 Python項目
#使用python開發的應用程式達到一定的規模之後,必然會出現多個子產品或者程式包目錄,同時除了源碼之外,說明性質的文本檔案,管理相關程式庫的元資訊等都會越來越多,這些為同一個目的服務的檔案,目錄以及元資訊,就是我們所說的項目。
一個完整的結構需要滿足以下的條件:
- 擁有一個在版本管理之下的源碼目錄
- 程式資訊在setup.py中定義
- 在一個virtualenv環境中運作
#如果項目符合标準,那麼它與工具之間就會有很強的親和力,而且便于今後自己或者其他的開發者進一步開發,另外,本章所介紹的結構記錄流程不但适合于個人的開發環境,也适用于團隊的開發環境。
3.2 環境與工具
3.2.1 使用virtualenv搭建獨立的環境
使用virtualenv為每一個項目搭建獨立的環境,具有以下的優點:
- 添加撤那個續保以及變更版本時,能将影響控制在目前的環境
- 便于判斷已經安裝的程式包是否可以删除
- 不再需要改環境時,可以直接删除整個環境
-
一旦出現了問題,那麼問題必然出現在該環境的項目上,有助于找到問題的所在
使用pip安裝外部程式庫時,庫會被安裝到python的安裝目錄下,不同目的的程式庫會被安裝到同一目錄下,不但容易導緻版本沖突,而且很難分辨出來哪些程式庫已經沒有用了。
virtualenv的主要特征展現在下列的功能上
- * 在virtualenv 環境中可以自由安裝python ,不需要提供作業系統管理者權限*
- * 在virtualev 環境下,可以根據目的不同安裝程式庫*
- * 可以随時關閉或者打開virtualenv 環境*
virtualenv 環境搭建的數量沒有上限
- 不同的環境裡面的庫沒有關系,互相之間沒有任何關系
- 建立virtualenv環境
virtualenv venv1
複制
- 激活環境
source venv/bin/activate
複制
- 查找對應的目錄
$python
>>>import sys
>>>sys.executable
複制
- 關閉環境
這裡寫代碼片(venv)$deactivate
複制
- 删除環境(首先需要關閉環境)
rm -R venv
複制
檔案結構與釋出程式包
在這一部分,我們會嘗試吧第二章中卡發的留言闆應用放到P有PI上面進行公開,在這個過程中學習一下setup.py 的寫法以及如何向PyPI上面上傳程式包。
3.3.1 編寫setup.py
setup.py 的功能,python的封裝離不開setup.py,封裝可以便于編寫的長須供其他使用者或者項目使用,封裝的大部分時間都要小号在白那些setup.py上面。這個名字實在python中定好的,不可以随便更改,我們會在這個檔案中定義程式包的名稱,包以及依賴包的資訊等中繼資料。另外,将程式包注冊到PyPI的操作也需要通過setup.py來進行。
setup.py的指令
首先,先制作一個可以運作的setup.py的空殼
setup.py
from setuptools import setup
setup(name='guestbook')
複制
setup.py的指令一覽如下圖:

下面我們來建立最基本的源碼包,源碼包需要通過python setup.py sdist指令來建立,如下圖所示:
檢視目錄如下所示:
現在,dist目錄下面已經生成了guestbook-0.0.0.tar.gz檔案,這個檔案目前隻包含setup.py。
注意!!在執行過程中我們看到了一些warning,這些waring 指出的項目最好都設定一下,我們将會在後面學會如何進行設定。
3.3.2 留言闆的項目結構
首先,我們先來了解一下python項目一般的目錄結構。當封裝對象隻有一個”.py “檔案時,其結構如下所示:
/home/chengyiming/project_name
+--MANIFEST.in
+--README.rst
+--packagename.py
+--setup.py
複制
如果封裝目錄下包含多個”.py “檔案時,其結構如下所示:
/home/chengyiming/project_name
+--MANIFEST.in
+--README.rst
+--packagename/
| +--__init__.py
| +--module.py
| +--templates/
| +--index.html
+--setup.py
複制
我們的留言闆應用有下述檔案組成:
檔案路徑 | 說明 |
---|---|
guestbooki.py | 伺服器程式 |
guestbook.dat | 送出資料檔案 |
static/main.css | CSS檔案 |
templates/index.html | 輸出的HTML的模闆,用于顯示“送出/留言清單”的頁面 |
雖然“.py”檔案隻有一個,但是static和templates目錄下都包含檔案,由于我們之前介紹的項目目錄無法安裝模闆等檔案,是以這裡需要使用最後一種項目檔案。最終檔案安排如下表所示:
?home/chengyiming/guestbook/
+--LICENSE.txt
+--MANIFEST.in
+--README.rst
| +--__init__.py
| +--static/main.css
| +--templates/index.html
+--setup.py
複制
現在我們來建立guestbook目錄,将guestbook.py檔案一發動到該目錄下并命名為init.py。templates和static目錄也要移動到guestbook目錄下,guestbook.dat 不是我們要釋出的東西,是以這裡不需要它。
接下來,我們來實際用用這個封裝用的結構
3.3.3 setup.py 與MANIFEST.in——設定程式包資訊與捆綁的檔案
接下來,我們将在setup.py中設定程式包的資訊,然後子啊MANIFEST.in 中制定捆綁的檔案,接下來依次了解一下。
setup.py
首先,我們描述一下guestbook項目的setup.py
from setuptools import setup,find_packages
setup(
name='guestbook',
version='1.0.0',
packages=find_packages(),
include_package_data=True,
install_requires=['Flask',],
)
複制
如果一個環境能夠使用pip,那麼這個環境一定安裝了setuptools庫。一般情況下,我們習慣使用setuptools提供的含有拓展功能的setup函數,下面來了解一下各個函數的意義:
-
name
程式包的名稱,一般情況下,包名與程式名一緻,但是一般情況下程式包的名字需要非常獨特才好,是以一般會在前面加上釋出的組織的名字,chengyiming.guestbook
-
version
代表版本号的字元串
-
packages
指定所有捆綁的python程式包(可以用python指令import 的目錄名),例如,如果一個項目包含多級目錄,那麼我們需要使用下例所示的方法,清單指定所有的程式包。
packages=['guestbook','guestbook.server','guestbooki.server.dir','guestbook.storage',......]
複制
find_packages()還可以自動搜尋目前目錄下的所有python程式包并傳回程式包的名稱,有了這個,我們便可以省去一個個列舉的麻煩。
-
include_package_data
在packages指定的python包(目錄)中,除了“.py”之外的檔案都稱為程式包資源,這個設定用來指定是否安裝了python包中所含的程式包資源。
這裡我們需要安裝templates和static這兩個程式包資源,是以将它們指定為True。
這一設定并不能将程式包資源與我們要釋出的程式包捆綁在一起,捆綁的方法将在MANIFEST.in中學習
-
install_requires
清單指定依賴包,留言闆應用要依賴Flask,是以在這裡我們指定Flask,與requirements.txt不同,這裡我們一般不指定版本。
MANIFEST.in
為了将HTML檔案,CSS檔案等程式包資源與程式包捆綁剛在一起,我們需要使用MANIFEST.in來制定封裝對象檔案。
這裡我們在setup.py所在的目錄下建立MANIFEST.in檔案,制定封裝對象檔案的範圍。
MANIFEST.in
recursive-include guestbook *.html,*.css
複制
recursive-include白哦是捆綁指定目錄下所有與制定類型一緻的檔案,在上面的代碼中,我們捆綁了guestbook目錄下所有與.html和.css一緻的檔案。
現在我們希望使用這個程式包的環境能夠安裝這些捆綁好的程式包資源,是以需要把錢買你提到的install_package_data指定為True,不能忘記奧~
MANIFEST.in還可以捆綁vguestbook應用不适用的非程式包資源檔案,比如LICENSE.txt,在釋出、程式包時最好把許可檔案也捆綁進去。
假設我們使用了BSD許可,并在LICENSE.txt檔案中描述了許可條款,接下來,我們需要在MANIFEST.in裡面添加對他的捆綁指定。
MANIFEST.in
recursive-include guestbook *.html *.css
include LICENSE.txt
複制
include會捆綁所有于指定類型一緻的檔案,是以再添加了上面的指定語句之後,LICENSES.txt就和程式包捆綁在了一起。
确定運作環境
- 搭建virtualenv環境及安裝
cd ..
virtualenv .venv
複制
2.如圖所示安裝的包
guestbook-1.0.0已經被安裝到了虛拟環境中,我們可以看到,記錄程式包原資料位置餓的guestbook.egg-link檔案被安裝到了virtualenv 環境中,easy-install.path檔案中添加了guestbook的源碼位置。/
這樣的話,我們在其他PC或伺服器上面建構環境是,就不必再一個個安裝依賴包,如果今後需要添加或者更改依賴庫,隻需要按照i前面的流程更新setup.py,然後再執行一次pip install即可。
setup.py——建立執行指令
第二章的留言闆項目是一個直接從python啟動的腳本,要想讓下載下傳他的人用起來更加友善,最好生成一些使用者指令,這裡外婆們通過設定setup.py,讓其自動生成guestbook指令。
我們在setup.py中添加了entry_points。這樣在安裝程式包時會自動生成guestbook指令。使用者執行guestbook指令是将會調用guestbook子產品的main函數。
但是guestbook/init.py中還沒有main函數,是以我們需要添加這個函數,代碼如下:
略
def main():
application.run('127.0.0.1',8000)
if __name__=='__main__':
application.run('127.0.0.1',8000,debug=True)
複制
建立用于的釋出的程式包時,執行python setup.py sdist指令
在dist目錄下生成了guestbook-1.0.0.tar.gz。這個tar.gz檔案中包含了guestbook/init.py,setup.py,LICENSE.txt,HTML,CSS等檔案,隻需要把這個檔案安裝到我們先安裝應用的環境中,就可以運作pip install guestbook-1.0.0.tar.gz,直接從檔案進行安裝。
3.3.6 送出至版本庫
我們先将之前的内容送出到版本庫,關于hg 的指令操作,在第一章和第六章有詳細的介紹,目前的目錄介紹如下所示:
/home/chengyiming/guestbook/
+--.venv/
+--LICENSE.txt
+--MANIFEST.in
+--guestbook
| +--__init__.py
| +--static/main.css
| +--templates/index.html
+--guestbook.dat
+--guestbook.egg-info/
+--setup.py
複制
在開發python項目時,我們習慣将setup.py放在版本庫最初級目錄(根目錄)下。這樣我們就能使用pip直接從版本庫進行安裝。
另外,有些檔案和目錄是不用儲存到版本庫中,guestbook.dat檔案的作用時記錄留言闆接收到的資料,這些資料沒必要記錄到版本庫中。
guestbook.egg-info目錄的作用是記錄程式包的中繼資料,.venv可以重新生成,沒必要儲存在版本庫
接下來,我們将除了以上三者的檔案送出給版本庫
cd ~/guestbook
hg init
hg add LICENSE.txt MANIFEST.in guestbook setup.py
hg ci -m "initial"
複制
3.3.7 README.rst——開發環境設定流程
以下介紹設定流程說明書,總結該留言闆應用開發環境的搭建流程,如下:
- clone項目的版本庫
- 搭建項目專用的virtualenv環境
-
在virtualenv環境内執行pip install (如果用于開發,執行pip install -e )
設定流程:
hg clone https://bitbucket.org/chengyiming/guestbook
cd guestbook
virtualenv .venv
source .venv/bin/activate
(.venv)$pip install .
(.venv)$guestbook
*Running on http://127.0.0.1:5000/
複制
我們将上圖的流程寫入README.rst檔案即可。
README.rst
==================
留言闆應用
==================
目的
=====
練習開發通過web浏覽器送出留言的web應用程式
工具版本
==============
:python:2.7.8
:pip: 1.5.6
:virtualenv:1.11.6
安裝與啟動方法
==================
從版本庫擷取代碼,然後在該目錄下搭建virtualenv環境:
$hg clone https://bitbucket.org/chengyiming/guestbook
$cd guestbook
$virtualenv .venv
$source .venv/bin/activate
(.venv)$pip install .
(.venv)$guestbook
開發流程
===========
用于開發的安裝
-----------------
1.檢測
2按照以下流程安裝
(.venv)$pip install -e .
複制
寫完之後記得将README.rst檔案送出到版本庫
3.3.8 變更依賴包
留言闆的依賴包是Flask,但是,我們在開發初期很難确定好一款應用所有的依賴包,有時候還會放棄目前的包而改用其他的,特别是周期段,釋出頻繁的項目,通常每釋出一次,就會變更一次依賴包。
使用pip 更換了程式包,這一步如何告知他人
(.venv)$pip install flask
(.venv)$pip install bottle
複制
留言闆的setup.py裡面記錄着依賴包的資訊,我們隻需要更改setup.py的設定即可。如果更改了setup.py的install _requires行,需要再次執行pip install -e
即使我們從fsetup.py中删除了flask,之前安裝到環境中的flask 以及其關聯的程式包也不會被解除安裝,若想删除沒有用的程式包,需要通過virtualenv –clear 。等方法重建環境。
重建環境如下所示:
(.venv)virtualenv –clear .venv #删除.venv環境内的全部依賴庫
(.venv)virtualenv –clear .venv #删除.venv環境内的全部依賴庫 (.venv)virtualenv –clear .venv #删除.venv環境内的全部依賴庫 (.venv)pip install -e #根據./setup.py安裝依賴庫
3.3.9 通過requirements.txt固定開發版本
我們不僅可以通過setup.py管理依賴包,還可以通過requirements.txt來管理依賴庫。
建立requiments.txt:
(.venv)$pip freeze >requirements.txt
其中記錄了目前環境已經安裝的所有程式包以及其明确的版本号
使用setiup.py管理依賴包時,沒有指定版本,這是兩者管理的一大差別
要想在其它環境中安裝同樣的程式包們,我們需要将這個檔案防盜蓋環境下,在安裝
(.venv)$pip install -r requirements.txt
這樣,環境中就安裝了同樣版本的程式包
3.3.10 Python setup.py bdist_wheel_制作用于wheel釋出的程式包
制作wheel程式包之前,我們先來安裝wheel
pipinstallwheel接下來,生成wheel程式包pipinstallwheel接下來,生成wheel程式包pip install wheel 接下來,生成wheel程式包 python setup.py bdist_wheel
ls dist/
上傳到PyPI進行公開
我們之是以可以通過pip指令安裝指定的程式包,是因為這些程式包都被注冊到了PyPI上面,PyPI時python的官方網站,所有人都能随意上傳以及下載下傳python程式包,如果各位不介意公開自己開發的程式包,不妨将其注冊在PyPI上。