從入門到精通:Python項目打包與setup.py實戰(zhàn)指南
1. 概述
在Python開發(fā)中,我們經(jīng)常需要將自己的代碼打包成可供其他人使用的庫或應(yīng)用程序。為了方便用戶安裝和使用,我們需要創(chuàng)建一個配置文件 setup.py,用于定義打包的相關(guān)信息和依賴項。本文將詳細介紹如何編寫 setup.py 文件,并展示每一步需要做什么。
1.1 為什么需要對項目分發(fā)打包?
平常我們習慣了使用 pip 來安裝一些第三方模塊,這個安裝過程之所以簡單,是因為模塊開發(fā)者為我們默默地為我們做了所有繁雜的工作,而這個過程就是 打包。
打包,就是將你的源代碼進一步封裝,并且將所有的項目部署工作都事先安排好,這樣使用者拿到后即裝即用,不用再操心如何部署的問題(如果你不想對照著一堆部署文檔手工操作的話)。
不管你是在工作中,還是業(yè)余準備自己寫一個可以上傳到 PyPI 的項目,你都要學會如何打包你的項目。
Python 發(fā)展了這么些年了,項目打包工具也已經(jīng)很成熟了。他們都有哪些呢?
你可能聽過 disutils、 distutils 、distutils2、setuptools等等,好像很熟悉,卻又很陌生,他們都是什么關(guān)系呢?
1.2 包分發(fā)的始祖:distutils
distutils 是 Python 的一個標準庫,從命名上很容易看出它是一個分發(fā)(distribute)工具(utlis),它是 Python 官方開發(fā)的一個分發(fā)打包工具,所有后續(xù)的打包工具,全部都是基于它進行開發(fā)的。
distutils 的精髓在于編寫 setup.py,它是模塊分發(fā)與安裝的指導(dǎo)文件。
那么如何編寫 setup.py 呢?這里面的內(nèi)容非常多,我會在后面進行詳細的解析,請你耐心往下看。
你有可能沒寫過 setup.py ,但你絕對使用過 setup.py 來做一些事情,比如下面這條命令,我們經(jīng)常用它來進行模塊的安裝。
python setup.py install
這樣的安裝方法是通過源碼安裝,與之對應(yīng)的是通過二進制軟件包的安裝,同樣我也會在后面進行介紹。
1.3 分發(fā)工具升級:setuptools
setuptools 是 distutils 增強版,不包括在標準庫中。其擴展了很多功能,能夠幫助開發(fā)者更好的創(chuàng)建和分發(fā) Python 包。大部分 Python 用戶都會使用更先進的 setuptools 模塊。
distribute,或許你在其他地方也見過它,這里也提一下。
distribute 是 setuptools 有一個分支版本,分支的原因可能是有一部分開發(fā)者認為 setuptools 開發(fā)太慢了。但現(xiàn)在,distribute 又合并回了 setuptools 中。因此,我們可以認為它們是同一個東西。
還有一個大包分發(fā)工具是 distutils2,其試圖嘗試充分利用distutils,setuptools 和 distribute 并成為 Python 標準庫中的標準工具。但該計劃并沒有達到預(yù)期的目的,且已經(jīng)是一個廢棄的項目。
因此,setuptools 是一個優(yōu)秀的,可靠的 Python 包安裝與分發(fā)工具。
2. setup.py 文件的創(chuàng)建
首先,我們需要在項目的根目錄下創(chuàng)建一個 setup.py 文件。這個文件將包含我們用于打包的配置信息。
3、詳解 setup.py 的編寫:
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: 包的名稱
version: (-V) 包的版本號
author: 包的作者姓名
author_email: 作者的電子郵件地址
maintainer 維護者
maintainer_email 維護者的郵箱地址
description: 包的簡要描述
long_description 程序的詳細描述
url: 包的項目主頁
platforms 程序適用的軟件平臺列表
3.1.1 程序分類信息
classifiers: 用于指定所屬分類的列表,例如所支持的Python版本、所使用的許可證等.所有支持的分類列表見:https://pypi.org/pypi?%3Aaction=list_classifiers
classifiers = [ # 發(fā)展時期,常見的如下 # 3 - Alpha # 4 - Beta # 5 - Production/Stable 'Development Status :: 3 - Alpha', # 開發(fā)的目標用戶 'Intended Audience :: Developers', # 屬于什么類型 'Topic :: Software Development :: Build Tools', # 許可證信息 'License :: OSI Approved :: MIT License', # 目標 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、包的進階信息:
data_files:(如果沒有可以不寫)裝過程中,需要安裝的靜態(tài)文件,如配置文件、service文件、圖片等??????
data_files=[ ('', ['conf/*.conf']), ('/usr/lib/systemd/system/', ['bin/*.service']), ],?
packages: (自動搜索 Python 包)包含的模塊列表(包含__init__.py的文件夾),這里通常使用 find_packages(),它默認在和setup.py同一目錄下搜索各個含有 __init__.py的包。 有些不想要進行打包的文件可以排除
packages=find_packages(exclude=["dist.*", "dist", "tests.*", "tests"]),
我們指定 packages 后會自動將指定的 package 下的源代碼進行打包。但是有的時候會有很多 subpackage,這個時候 setuptools 提供了 find_packages 來找到所有的 subpackages。
install_requires:(自動安裝依賴)
install_requires = ["requests"]: 需要安裝的依賴包。我們可以首先生成 requirements.txt 文件,接著使用生成的文件生成需要的參數(shù)。關(guān)于生成 requirements.txt 文件,可以參考Python自動生成requirements.txt文件。
這個參數(shù)是在 setup.py 文件中指定依賴,然后在使用 setuptools 安裝應(yīng)用時,依賴包的相應(yīng)版本就會被自動安裝。但是通常情況下,手動寫依賴會比較麻煩,我們可以使用 pipreqs 首先自動生成 requirement.txt 文件,接著讀取這部分文件即可。
關(guān)于 install_requires, 有以下五種常用的表示方法:
'argparse',只包含包名。這種形式只檢查包的存在性,不檢查版本。方便,但不利于控制風險。
'setuptools==38.2.4',指定版本。這種形式把風險降到了最低,確保了開發(fā)、測試與部署的版本一致,不會出現(xiàn)意外。缺點是不利于更新,每次更新都需要改動代碼。
'docutils >= 0.3',這是比較常用的形式。當對某個庫比較信任時,這種形式可以自動保持版本為最新。
'Django >= 1.11, != 1.11.1, <= 2',這是比較復(fù)雜的形式。如這個例子,保證了Django的大版本在1.11和2之間,也即1.11.x;并且,排除了已知有問題的版本1.11.1(僅舉例)。對于一些大型、復(fù)雜的庫,這種形式是最合適的。
'requests[security, socks] >= 2.18.4',這是包含了額外的可選依賴的形式。正常安裝requests會自動安裝它的install_requires中指定的依賴,而不會安裝security和socks這兩組依賴。這兩組依賴是定義在它的extras_require中。這種形式,用在深度使用某些庫時。
include_package_data: 引入非 Python 文件。默認情況下只會對 Python 源碼進行打包,但是如果我們想要將其他靜態(tài)文件,例如 css 文件,或是 qt 的一些 ui 文件打包進去,就需要使用這個參數(shù)。后面會有詳細的介紹。
ext_modules
ext_modules參數(shù)用于構(gòu)建 C 和 C++ 擴展擴展包。其是 Extension 實例的列表,每一個 Extension 實例描述了一個獨立的擴展模塊,擴展模塊可以設(shè)置擴展包名,頭文件、源文件、鏈接庫及其路徑、宏定義和編輯參數(shù)等。如:
setup( # other arguments here... ext_modules=[ Extension('foo', glob(path.join(here, 'src', '*.c')), libraries = [ 'rt' ], include_dirs=[numpy.get_include()]) ] )
詳細了解可參考:2. Writing the Setup Script — Python 3.6.15 documentation
3.3、制作命令行工具:
entry_points: 動態(tài)發(fā)現(xiàn)服務(wù)和插件,可以用來制作命令行工具。也就是我們可以通過一些簡單的命令,來運行 Python 項目中的指定文件或是函數(shù)。下面會詳細進行介紹。
entry_points 的說明
entry_points 可以用來創(chuàng)建控制臺腳本。我們看上面的例子就會非常好理解:
entry_points = { 'console_scripts': [ 'test = test.help:main' ] }
這樣在安裝完畢之后,我們可以直接在控制臺輸入 test,這樣是可以運行 test.help 模塊下的 main 函數(shù)。
4、執(zhí)行安裝文件
在有了上面的 setup.py 文件之后,我們就可以進行打包,也可以將應(yīng)用安裝在本地的 Python 環(huán)境中了。一共有以下的四種安裝方式:
4.1、創(chuàng)建 egg 包
下面的命令會在當前目錄下的 dist 目錄內(nèi)創(chuàng)建一個 egg 文件。文件名格式就是 應(yīng)用名-版本號-Python版本.egg。同時你會注意到,當前目錄多了 build 和 應(yīng)用名.egg-info 子目錄來存放打包的中間結(jié)果。(主要是看 dist 目錄下的內(nèi)容)
python setup.py bdist_egg
4.2、創(chuàng)建 tar.gz 包
這個命令和上例類似,只不過創(chuàng)建的文件類型是 tar.gz,文件名為 應(yīng)用名-版本號.tar.gz。也是保存在 dist 文件夾下。
python setup.py sdist --formats=gztar
4.3、安裝應(yīng)用
下面的安裝命令會將當前的 Python 應(yīng)用安裝到當前 Python 環(huán)境的 site-packages 目錄下,這樣其他程序就可以像導(dǎo)入標準庫一樣導(dǎo)入該應(yīng)用的代碼了。
python setup.py install # 或者 pip install . # 暫時還沒有測試
這里我們?nèi)绻胍獎h除安裝的包,可以使用 pip uninstall xxx 來完成刪除。
4.4、以開發(fā)方式安裝
如果應(yīng)用在開發(fā)過程中會頻繁變更,每次安裝還需要先將原來的版本卸掉,這樣就會很麻煩。如果使用 develop 開發(fā)方式安裝的話,應(yīng)用代碼不會真的被拷貝到本地 Python 環(huán)境的 site-packages 目錄下,而是在 site-packages 目錄里創(chuàng)建一個指向當前應(yīng)用位置的鏈接。這樣如果當前位置的源碼被改動,就會馬上反映到 site-packages 里。
python setup.py develop
或者也可以使用命令
pip install -e .
是 pip 命令的一種使用方式,它表示在當前目錄下安裝一個可編輯包。具體含義如下:
- pip 是 Python 的軟件包管理器,用于安裝、卸載和管理 Python 包;
- install 是 pip 命令的一個子命令,用于安裝 Python 包;
- -e 表示使用可編輯模式安裝包,即把包安裝到當前目錄,并且可以通過編輯包代碼實時調(diào)試;
- . 表示安裝當前目錄下的包。
因此,pip install -e . 的含義是:在當前目錄下安裝一個包,并創(chuàng)建一個軟連接引用該包(而不是將包復(fù)制到 site-packages 目錄下)。這個軟連接是一個指向包代碼的符號鏈接,它可以使包的修改直接反映到當前目錄下的項目中,從而方便開發(fā)和調(diào)試。
到此這篇關(guān)于從入門到精通:Python項目打包與setup.py實戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Python項目打包與setup.py內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python+OpenCV實現(xiàn)基于顏色的目標識別
這篇文章主要介紹了利用OpenCV實現(xiàn)基于顏色的目標識別,即讓攝像頭識別到視野范圍內(nèi)的有顏色的氣球并返回每個氣球的中心點坐標,感興趣的可以跟隨小編學習一下2022-01-01Anaconda 查看、創(chuàng)建、管理和使用python環(huán)境的方法
這篇文章主要介紹了Anaconda 查看、創(chuàng)建、管理和使用python環(huán)境的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12在前女友婚禮上用python把婚禮現(xiàn)場的WIFI名稱改成了
大家好,我是Lex 喜歡欺負超人那個Lex 擅長領(lǐng)域:python開發(fā),網(wǎng)絡(luò)安全滲透,Windows域控Exchange架構(gòu) 今日重點:python暴力拿下WiFi密碼;python拿下路由器管理頁面 代碼干貨滿滿,建議收藏+實操!有問題及需要,請留言哦2021-08-08