Python3基礎之構建setup.py
技術背景
在上一篇博客中,我們介紹了如何使用pyinstaller將python項目打包成一個可執行文件,並且放在系統目錄下,讓系統用戶可以直接識別到我們構造的項目。而python項目中常見的setup.py
其實也是在執行類似的構建的功能,通過setup.py文件可以將python包按照指定的方案進行構建,構建出來的可執行文件是一個egg
文件。最後將這個egg文件轉移到python包的統一管理路徑下,這樣我們就可以在系統內任一位置的python文件中調用我們構建好的這個python庫。
python項目示例
首先我們構造一個大概的目錄結構,項目的路徑如下所示:
[dechin@dechin-manjaro test_setup]$ tree
.
├── requirements.txt
├── setup.py
└── ts
└── __init__.py
1 directory, 3 files
在一個名為test_setup
的路徑下,作為我們最上層的項目根目錄。然後在根目錄下有需求配置文件requirements.txt
,我們可以在這個文件中添加我們的python庫所依賴的其他python庫,如numpy
、scipy
等。而setup.py
就是我們這裡的安裝文件,在後面的章節中會着重提到。最後是我們的項目的核心路徑ts
,裏面包含了我們的核心代碼。
用__init__.py文件構造的簡單項目
在一個普通的python項目中,我們可以用目錄.模塊名.函數名
的形式來構造python項目的引用方法。但是對於一些比較簡單的庫而言,比如定義一個二叉樹的數據結構這種簡單的項目,我們可以直接在__init__.py
文件裏面直接定義好所有的項目函數及內容。當然,對於一些比較大型的比較規範的項目而言,也會用__init__.py
文件作為一個統一的函數入口,以提升模塊化項目的可用性。在本測試用例中,我們也定義了一個簡單的py核心代碼文件如下:
[dechin@dechin-manjaro test_setup]$ cat ts/__init__.py
# __init__.py
def p2(number):
return number ** 2
def p3(number):
return number ** 3
這個名為ts
的項目具有兩個函數功能:p2
用於計算輸入參數的平方,以及p3
用於計算輸入參數的立方。
構造setup文件
我們主要是基於setuptools來實現一個python項目的構建,以下直接展示本項目的構建方法:
# setup.py
import os
from setuptools import setup, find_packages
__version__ = '1.0' # 版本號
requirements = open('requirements.txt').readlines() # 依賴文件
setup(
name = 'ts', # 在pip中顯示的項目名稱
version = __version__,
author = 'Dechin',
author_email = '[email protected]',
url = '',
description = 'ts: Test Setup',
packages = find_packages(exclude=["tests"]), # 項目中需要拷貝到指定路徑的文件夾
python_requires = '>=3.5.0',
install_requires = requirements # 安裝依賴
)
在這個構建方法中,我們配置了項目的版本號(版本管理)、依賴庫、項目名稱以及需要進行構建的文件夾。比如這裡我們加了一個exclude
的選項排除了tests
目錄(雖然本項目中並沒有這個目錄,但是一般我們都要剔除測試目錄)。當然我們也可以用指定目錄進行構建的方法,但是這裡不做過多的贅述。
依賴包配置文件
python之所以這麼火,很大程度上就得益於其強大的生態,而這些生態都是靠別人搭建好的輪子來支撐起來的。因此大部分的python項目都會依賴於第三方的python包,在安裝的時候我們可以僅用一個文件就進行配置:
[dechin@dechin-manjaro test_setup]$ cat requirements.txt
numpy==1.20.1
在requirements.txt
的配置文件中,我們最好是能夠指定一個固定的版本號,這樣可以確保軟件的兼容性。
執行安裝
按照上述的方法對我們的python項目進行編寫後,就可以開始執行構建,如果需要測試編譯可以先運行python3 setup.py build
來進行測試,在安裝成功後再執行install
指令,當然我們也可以直接一步執行python3 setup.py install
指令來進行安裝:
[dechin@dechin-manjaro test_setup]$ python3 setup.py install
running install
running bdist_egg
running egg_info
writing ts.egg-info/PKG-INFO
writing dependency_links to ts.egg-info/dependency_links.txt
writing requirements to ts.egg-info/requires.txt
writing top-level names to ts.egg-info/top_level.txt
reading manifest file 'ts.egg-info/SOURCES.txt'
writing manifest file 'ts.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-x86_64/egg
running install_lib
running build_py
creating build/lib
creating build/lib/ts
copying ts/__init__.py -> build/lib/ts
creating build/bdist.linux-x86_64/egg
creating build/bdist.linux-x86_64/egg/ts
copying build/lib/ts/__init__.py -> build/bdist.linux-x86_64/egg/ts
byte-compiling build/bdist.linux-x86_64/egg/ts/__init__.py to __init__.cpython-38.pyc
creating build/bdist.linux-x86_64/egg/EGG-INFO
copying ts.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO
copying ts.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying ts.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying ts.egg-info/requires.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying ts.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
zip_safe flag not set; analyzing archive contents...
creating 'dist/ts-1.0-py3.8.egg' and adding 'build/bdist.linux-x86_64/egg' to it
removing 'build/bdist.linux-x86_64/egg' (and everything under it)
Processing ts-1.0-py3.8.egg
Copying ts-1.0-py3.8.egg to /home/dechin/anaconda3/lib/python3.8/site-packages
Adding ts 1.0 to easy-install.pth file
Installed /home/dechin/anaconda3/lib/python3.8/site-packages/ts-1.0-py3.8.egg
Processing dependencies for ts==1.0
Searching for numpy==1.20.1
Best match: numpy 1.20.1
Adding numpy 1.20.1 to easy-install.pth file
Installing f2py script to /home/dechin/anaconda3/bin
Installing f2py3 script to /home/dechin/anaconda3/bin
Installing f2py3.8 script to /home/dechin/anaconda3/bin
Using /home/dechin/anaconda3/lib/python3.8/site-packages
Finished processing dependencies for ts==1.0
安裝完成後,我們可以在pip的管理包目錄下找到我們所構建的python包:
[dechin@dechin-manjaro test_setup]$ python3 -m pip list
Package Version
---------------------------------- -------------------
ts 1.0
同時在執行完build指令之後,本地目錄下會生成一系列的編譯構建目錄,如build和dist等:
[dechin@dechin-manjaro test_setup]$ tree
.
├── build
│ └── bdist.linux-x86_64
├── dist
│ └── ts-1.0-py3.8.egg
├── requirements.txt
├── setup.py
├── ts
│ ├── __init__.py
│ └── __pycache__
│ └── __init__.cpython-38.pyc
└── ts.egg-info
├── dependency_links.txt
├── PKG-INFO
├── requires.txt
├── SOURCES.txt
└── top_level.txt
6 directories, 10 files
而dist目錄下的egg文件在執行完install指令之後,會被拷貝到系統指定的python包管理路徑下,我們可以在系統中搜索到這個文件:
[dechin-root test_setup]# find / -name *ts-1.0-py3.8.egg
/home/dechin/anaconda3/lib/python3.8/site-packages/ts-1.0-py3.8.egg
/home/dechin/projects/2021-python/setup/test_setup/dist/ts-1.0-py3.8.egg
這裡我們可以看到第一個路徑就是python包管理路徑。
軟件包功能測試
在安裝完成後,我們可以在任意的路徑下引用到我們構建好的ts
項目,比如這裡我們可以用ipython來測試一下:
[dechin@dechin-manjaro test_setup]$ ipython
Python 3.8.5 (default, Sep 4 2020, 07:30:14)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from ts import p2, p3
In [2]: p2(4)
Out[2]: 16
In [3]: p3(4)
Out[3]: 64
測試結果表明,我們成功的從編譯構建好的ts項目中引用了平方和立方的計算函數。
安裝包的刪除
跟其他的python包一樣,我們可以用pip來統一管理,也可以用pip來直接刪除我們自己安裝的ts項目:
[dechin@dechin-manjaro test_setup]$ python3 -m pip uninstall ts
Found existing installation: ts 1.0
Uninstalling ts-1.0:
Would remove:
/home/dechin/anaconda3/lib/python3.8/site-packages/ts-1.0-py3.8.egg
Proceed (y/n)? y
Successfully uninstalled ts-1.0
總結概要
一個完善的python項目,不僅需要梳理好核心代碼的軟件架構,還需要定義好依賴文件、編譯構建文件、API接口文檔、編碼規範門禁等。這裡我們介紹了如何用setup.py文件來完善一個最簡單的python項目,這也是每一個python開源項目所必須要具備的條件。
版權聲明
本文首發鏈接為://www.cnblogs.com/dechinphy/p/setup.html
作者ID:DechinPhy
更多原著文章請參考://www.cnblogs.com/dechinphy/