python項目打包成可安裝的package
作者:elfin 資料來源:setuptools
- 1、資源介紹
- 2、環境准備
- 3、項目配置
- 4、setup函數的參數
- 4.01 name
- 4.02 version
- 4.03 description(可選)
- 4.04 url(可選)
- 4.05 auther(可選)
- 4.06 licence協議(可選)
- 4.07 classifiers(可選)
- 4.08 keywords(可選)
- 4.09 project_urls(可選)
- 4.10 packages
- 4.11py_modules
- 4.12 install_requires(可選)
- 4.13 package_dir(可選)
- 4.14 python_requires
- 4.15 package_data(可選)
- 4.16 data_files(可選)
- 4.17 scripts、entry_points、console_scripts(可選)
- 5、案例
1、資源介紹
關於python如何將一個項目打包成安裝包,官網有詳細的教程,這里是基於此教程做的一個demo。
資料:PyPA » Python Packaging User Guide » Guides » Packaging and distributing projects
項目打包與項目發布--Packaging and distributing projects
-
本文介紹如何配置、打包和分發您自己的Python項目的基礎知識。並假設您已經熟悉安裝包的內容。
-
本文的目的不是從整體上介紹Python項目開發的最佳實踐。例如,它不為版本控制、文檔或測試提供指導或工具建議。
-
有關更多參考資料,請參閱setuptools文檔中的Building and distribution Packages,但請注意,其中的一些建議內容可能已經過時。如果發生沖突,請參閱Python打包用戶指南中的建議。
2、環境准備
要打包自己的python項目,那么肯定第一步得先有一個python環境,這里默認環境已經准備好了,關於這部分內容可以參考:
如果要發布打包好的python項目,我們需要安裝twine這個庫:
-
pip install twine
3、項目配置
在項目配置前,我們需要明確:以下文件是你需要進行創建的:
項目根路徑
- [setup.py](#3.1 setup.py簡介)
- [setup.cfg](#3.2 setup.cfg簡介)
- [README.rst / README.md](#3.3 README文件)
- [MANIFEST.in](#3.4 MANIFEST.in)
- [LICENSE.txt](#3.5 LICENSE.txt簡介)
- [<你的項目>](#3.6 <你的項目>)
3.1 setup.py簡介
最重要的文件是setup.py它存在於項目目錄的根目錄中。有關示例,請參見在PyPA sample project中的 setup.py 。
setup.py
的兩個主要功能:
-
它是配置項目各個方面的文件。它的主要特點是它包含一個全局setup()函數。此函數的關鍵字參數是定義了項目的特定細節是什么樣的。最相關的論點將在下面一節中解釋。
-
它是用於運行與打包任務相關的各種命令的命令行接口。要獲取可用命令的列表,請運行
python setup.py --help-commands
命令。此命令是基於項目的setup.py進行help命令提示的!以下代碼段是官方測試項目的help結果:>>> python setup.py --help-commands Standard commands: 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: 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' dist_info create a .dist-info directory 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 (deprecated) 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
這一段項目並沒有聲明,應該是setuptools所做的標准工作!
3.2 setup.cfg簡介
setup.cfg是包含選項默認值的ini文件。如 PyPA sample project中的 setup.cfg 。
[metadata]
# This includes the license file(s) in the wheel.
# https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file
license_files = LICENSE.txt
3.3 README文件
這個文件是項目的介紹文件,一般在Github上在主頁顯示,在python庫中就是用於描述的長文本,會顯示與庫的主頁。這里支持rst
和md
兩種格式。
注意:如果項目使用的setuptools>=0.6.27
,則有標准的自訴文件(README.rst
, README.txt
, or README
),默認情況下包含在發布源中。內置的distutils庫從python3.7開始采用這種方式。此外,setuptools 36.4.0+
將包括README.md如果找到了。如果使用setuptools
,你不需要將readme文件羅列到MANIFEST.in文件中。
3.4 MANIFEST.in
當您需要打包未自動包含在源分發中的其他文件時,需要清單文件。有關編寫清單文件的詳細信息,包括默認情況下包含的內容的列表,請參閱“Including files in source distributions with MANIFEST.in”。
當我們對項目構建源代碼發布版時,只有部分文件被默認包含在內。你很有可能希望包含其他文件在這個源代碼中,如authors/contributors
文件、介紹文件夾、數據集等。最初README文件沒有默認添加時,對於長描述文字,我們還要手動將其添加到MANIFEST.in
文件中。
通過編寫項目根路徑下的MANIFEST.in
文件,可以添加、刪除文件(在打包時)。
項目打包時,默認包含的文件:
- 通過
setup()
參數packages和參數py_modules包含的所有的python文件; - 通過和
setup()
參數libraries
和參數ext_modules
提到的所有的C文件; - 通過
scripts setup()
參數指定的腳本; - 通過
package_data
和data_files
setup()
參數指定的所有文件; - 通過
setup.cfg
(setuptools 40.8.0+)中的license_file
可選項指定的文件; - 通過
setup.cfg
(setuptools 42.0.0+)中的license_files
可選項指定的所有文件; - 所有滿足
test/test*.py
模式的文件; - setup.py;
- setup.cfg;
- README;
- README.txt;
- README.rst (Python 3.7+ or setuptools 0.6.27+);
- README.md (setuptools 36.4.0+);
- pyproject.toml (setuptools 43.0.0+);
- MANIFEST.in;
關於此文件的添加、刪除命令可參考官網。
3.5 LICENSE.txt簡介
每個軟件包都應該包含一個許可證文件,詳細說明分發條款。在許多司法管轄區,沒有明確許可證的軟件包不能由版權持有人以外的任何人合法使用或分發。如果您不確定要選擇哪個許可證,可以參考GitHub的“選擇許可證”或咨詢律師等資源。
3.6 <你的項目>
盡管這不是必需的,但最常見的做法是將Python模塊和包放含在一個根目錄下的包中,該包與您的項目同名或非常接近。
4、setup函數的參數
如上所述setup.py它包含一個全局setup()函數。此函數的關鍵參數本章詳細介紹。更多可參考PyPA sample project。
4.01 name
定制項目的名字,它決定了你的項目在PyPI的陳列。名字必須滿足下列要求:
- 只能包含ASCII編碼的字母、數字、下划線、連字符(-)、句號(.);
- 並且只能由ASCII編碼的字母和數字開頭。
注意事項:
- 名字不區分大小寫;
- 將任意長的下划線、連字符和/或句點視為相等。
4.02 version
這個關鍵字見名知義,是當前項目的版本。
這是您的項目的當前版本,允許您的用戶確定他們是否有最新版本,並指示他們已針對哪些特定版本測試了自己的軟件。
如果發布項目,則每個版本的release都會顯示在PyPI上。
有關如何使用version向用戶傳遞兼容性信息的更多信息,請參見選擇版本控制方案。
4.03 description(可選)
項目描述,如果你發布到PyPI,則會展示到項目主頁。關於此描述,你可以隨意配置。
一般我們會使用README文件,如:
from setuptools import setup, find_packages
here = pathlib.Path(__file__).parent.resolve()
long_description = (here / 'README.md').read_text(encoding='utf-8')
setup(
……
description='A sample Python project',
long_description=long_description,
long_description_content_type='text/markdown',
……
)
4.04 url(可選)
你的項目主頁,一般我們的項目都放在Github上面,根據你的實際情況設置就好了!
4.05 auther(可選)
注明開發者的相關信息
author='A. Random Developer',
author_email='author@example.com',
4.06 licence協議(可選)
這個參數建議一定要設置。你如果不想設置,也沒多大個事!
4.07 classifiers(可選)
classifiers=[ # Optional
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
# Indicate who your project is intended for
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools',
# Pick your license as you wish
'License :: OSI Approved :: MIT License',
# Specify the Python versions you support here. In particular, ensure
# that you indicate you support Python 3. These classifiers are *not*
# checked by 'pip install'. See instead 'python_requires' below.
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3 :: Only',
],
提供對項目進行分類的分類器列表。關於項目可配置的的參數可以參考官網列表。官網說明了CUDA、系統、框架等基本參數說明。classifiers實際上是用於項目搜索時的一個配置參數,你在classifiers設置的關鍵字有助於別人搜索到你的項目。
盡管分類器列表通常用於聲明項目支持的Python版本,但此信息僅用於搜索和瀏覽PyPI上的項目,而不用於安裝項目。要實際限制項目可以安裝在哪些Python版本上,請使用Python_requires參數。
4.08 keywords(可選)
描述項目的關鍵字,如Github中右側項目名下的關鍵字!
4.09 project_urls(可選)
project_urls={
'Documentation': 'https://packaging.python.org/tutorials/distributing-packages/',
'Funding': 'https://donate.pypi.org',
'Say Thanks!': 'http://saythanks.io/to/example',
'Source': 'https://github.com/pypa/sampleproject/',
'Tracker': 'https://github.com/pypa/sampleproject/issues',
},
列出有關項目的其他相關URL。這是鏈接到bug跟蹤器、源代碼存儲庫或支持包開發的地方。key的字符串是將在PyPI上顯示精確文本。
4.10 packages
packages=find_packages(include=['sample', 'sample.*']),
packages參數用於設置哪些包需要被打包!
4.11py_modules
py_modules=["six"],
若你的項目中有單獨的python文件,如在根目錄下有py文件,你需要使用這個參數讓setuptools知道你要打包這些文件。
4.12 install_requires(可選)
install_requires=['peppercorn'],
我們設置需要安裝的依賴!如果你有依賴,這里根據實際情況設置就好了!
4.13 package_dir(可選)
package_dir={'': 'src'}, # Optional
若你的項目package是根目錄下的一個文件夾,就需要設置這個參數
4.14 python_requires
python_requires='>=3',
# or 如果您的軟件包是針對Python3.3及更高版本的,但您還不願意承諾支持Python4
python_requires='~=3.3',
指定python的版本需求。
4.15 package_data(可選)
package_data={
'sample': ['package_data.dat'],
},
通常,需要在包中安裝其他文件。這些文件通常是與包的實現密切相關的數據,或者是包含使用包的程序員可能感興趣的文檔的文本文件。這些文件稱為“包數據”。
該值必須是從包名到應復制到包中的相對路徑名列表的映射。路徑被解釋為相對於包含包的目錄。
4.16 data_files(可選)
data_files=[('my_data', ['data/data_file'])],
如果你的數據位於項目之外,那么你就需要配置data_files參數來實現了!如果您需要安裝其他程序使用的文件,而這些程序可能不知道Python包,那么它非常有用。
如上面的配置會將my_data創建在庫的根目錄下。
4.17 scripts、entry_points、console_scripts(可選)
一般都是使用console_scripts,
entry_points={ # Optional
'console_scripts': [
'sample=sample:main',
],
},
5、案例
這里我們准備了一個繪制混淆矩陣的python項目,項目的依賴比較簡單,只依賴於python庫:sklearn、matplotlib、seaborn、pandas。
項目已經發布到github上,歡迎下載測試,地址:https://github.com/firstelfin/confusion
5.1 README.md准備
在Confusion項目根目錄下准備README文件,這里我習慣使用MD文件,具體可參考項目Confusion。
5.2 書寫setup.py文件
#!/usr/bin/python3
# -*- coding:utf-8 -*-
# Author: elfin-2020
# @Time: 2021/1/28 9:37
# project: confusion
from setuptools import setup, find_packages
import pathlib
here = pathlib.Path(__file__).parent.resolve()
# Get the long description from the README file
long_description = (here / 'README.md').read_text(encoding='utf-8')
setup(
name="confusion",
version="1.0.0",
description='A confusion matrix display project for python',
long_description=long_description,
long_description_content_type='text/markdown',
url="https://github.com/firstelfin/Confusion",
author='firstelfin',
classifiers=[
"Natural Language :: English",
"Natural Language :: Chinese(Simplified)",
"Natural Language :: Chinese(Traditional)",
"Programming Language :: python :: 3",
],
keywords='ConfusionMatrix, Display',
package_dir={'': 'confusion'},
packages=find_packages(where='confusion'),
py_modules=["display"],
python_requires="~=3.6",
install_requires=["sklearn", "matplotlib", "seaborn", "pandas"],
entry_points={
'console_scripts': [
'confusion=confusion.display:main', # 這一行代碼有問題后面會修改
],
},
)
5.3 嘗試在windows10上安裝
先進行創建:
python setup.py build
運行結果:
running build
running build_py
creating build
creating build\lib
copying confusion\display.py -> build\lib
creating build\lib\utils
copying confusion\utils\Draw.py -> build\lib\utils
copying confusion\utils\__init__.py -> build\lib\utils
這里我在之前的虛擬環境上測試,python=3.6,依賴是已經滿足的。如上創建setup.py后,項目的目錄結構如下:

由setup.py可知,打包的項目package_dir={'': 'confusion'}是圖中的藍色文件夾,你安裝后的庫名就是設置的confusion,注意你如果指定的package_dir名字和你的項目name不一樣,你使用name導入會報錯!
5.4 查看build的目錄結構

5.5 安裝與測試
進入虛擬環境安裝:
#安裝命令:
python setup.py install
運行結果:
點擊展開代碼
running install
running bdist_egg
running egg_info
creating confusion\confusion.egg-info
writing confusion\confusion.egg-info\PKG-INFO
writing dependency_links to confusion\confusion.egg-info\dependency_links.txt
writing entry points to confusion\confusion.egg-info\entry_points.txt
writing requirements to confusion\confusion.egg-info\requires.txt
writing top-level names to confusion\confusion.egg-info\top_level.txt
writing manifest file 'confusion\confusion.egg-info\SOURCES.txt'
reading manifest file 'confusion\confusion.egg-info\SOURCES.txt'
writing manifest file 'confusion\confusion.egg-info\SOURCES.txt'
installing library code to build\bdist.win-amd64\egg
running install_lib
running build_py
creating build\bdist.win-amd64
creating build\bdist.win-amd64\egg
copying build\lib\display.py -> build\bdist.win-amd64\egg
creating build\bdist.win-amd64\egg\utils
copying build\lib\utils\Draw.py -> build\bdist.win-amd64\egg\utils
copying build\lib\utils\__init__.py -> build\bdist.win-amd64\egg\utils
byte-compiling build\bdist.win-amd64\egg\display.py to display.cpython-36.pyc
byte-compiling build\bdist.win-amd64\egg\utils\Draw.py to Draw.cpython-36.pyc
byte-compiling build\bdist.win-amd64\egg\utils\__init__.py to __init__.cpython-36.pyc
creating build\bdist.win-amd64\egg\EGG-INFO
copying confusion\confusion.egg-info\PKG-INFO -> build\bdist.win-amd64\egg\EGG-INFO
copying confusion\confusion.egg-info\SOURCES.txt -> build\bdist.win-amd64\egg\EGG-INFO
copying confusion\confusion.egg-info\dependency_links.txt -> build\bdist.win-amd64\egg\EGG-INFO
copying confusion\confusion.egg-info\entry_points.txt -> build\bdist.win-amd64\egg\EGG-INFO
copying confusion\confusion.egg-info\requires.txt -> build\bdist.win-amd64\egg\EGG-INFO
copying confusion\confusion.egg-info\top_level.txt -> build\bdist.win-amd64\egg\EGG-INFO
zip_safe flag not set; analyzing archive contents...
creating dist
creating 'dist\confusion-1.0.0-py3.6.egg' and adding 'build\bdist.win-amd64\egg' to it
removing 'build\bdist.win-amd64\egg' (and everything under it)
Processing confusion-1.0.0-py3.6.egg
Copying confusion-1.0.0-py3.6.egg to l:\elfin-project\confusiontest\venv\lib\site-packages
Adding confusion 1.0.0 to easy-install.pth file
Installing confusion-script.py script to L:\elfin-project\ConfusionTest\venv\Scripts
Installing confusion.exe script to L:\elfin-project\ConfusionTest\venv\ScriptsInstalled l:\elfin-project\confusiontest\venv\lib\site-packages\confusion-1.0.0-py3.6.egg
Processing dependencies for confusion==1.0.0
Searching for pandas==1.1.5
Best match: pandas 1.1.5
Adding pandas 1.1.5 to easy-install.pth fileUsing l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for seaborn==0.11.1
Best match: seaborn 0.11.1
Adding seaborn 0.11.1 to easy-install.pth fileUsing l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for matplotlib==3.3.3
Best match: matplotlib 3.3.3
Adding matplotlib 3.3.3 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for sklearn==0.0
Best match: sklearn 0.0
Adding sklearn 0.0 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for python-dateutil==2.8.1
Best match: python-dateutil 2.8.1
Adding python-dateutil 2.8.1 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for pytz==2020.5
Best match: pytz 2020.5
Adding pytz 2020.5 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for numpy==1.19.5
Best match: numpy 1.19.5
Adding numpy 1.19.5 to easy-install.pth file
Installing f2py-script.py script to L:\elfin-project\ConfusionTest\venv\Scripts
Installing f2py.exe script to L:\elfin-project\ConfusionTest\venv\Scripts
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for scipy==1.5.4
Best match: scipy 1.5.4
Adding scipy 1.5.4 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for kiwisolver==1.3.1
Best match: kiwisolver 1.3.1
Adding kiwisolver 1.3.1 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for cycler==0.10.0
Best match: cycler 0.10.0
Adding cycler 0.10.0 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for Pillow==8.1.0
Best match: Pillow 8.1.0
Adding Pillow 8.1.0 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for pyparsing==2.4.7
Best match: pyparsing 2.4.7
Adding pyparsing 2.4.7 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for scikit-learn==0.24.1
Best match: scikit-learn 0.24.1
Adding scikit-learn 0.24.1 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for six==1.15.0
Best match: six 1.15.0
Adding six 1.15.0 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for joblib==1.0.0
Best match: joblib 1.0.0
Adding joblib 1.0.0 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Searching for threadpoolctl==2.1.0
Best match: threadpoolctl 2.1.0
Adding threadpoolctl 2.1.0 to easy-install.pth file
Using l:\elfin-project\confusiontest\venv\lib\site-packages
Finished processing dependencies for confusion==1.0.0
這里安裝了很多包,而且沒有報錯,最后顯示Finished processing dependencies for confusion==1.0.0
。
測試:

這里截屏軟件沒有將繪制的圖形截取到……
至此項目安裝完成!
5.6 entry_points生成的exe測試
這里測試confusion.exe報錯:
Traceback (most recent call last):
File "L:\elfin-project\ConfusionTest\venv\Scripts\confusion-script.py", line 33, in <module>
sys.exit(load_entry_point('confusion==1.0.0', 'console_scripts', 'confusion')())
File "L:\elfin-project\ConfusionTest\venv\lib\site-packages\pkg_resources\__init__.py", line 474, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "L:\elfin-project\ConfusionTest\venv\lib\site-packages\pkg_resources\__init__.py", line 2846, in load_entry_point
return ep.load()
File "L:\elfin-project\ConfusionTest\venv\lib\site-packages\pkg_resources\__init__.py", line 2450, in load
return self.resolve()
File "L:\elfin-project\ConfusionTest\venv\lib\site-packages\pkg_resources\__init__.py", line 2456, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
ModuleNotFoundError: No module named 'confusion'
執行完confusion.exe,回到python環境,查看confusion庫是存在的,但是不能導入了!!難道是兩個指令有沖突?
修改entry_points里面的key:
entry_points={
'console_scripts': [
'confusionDraw=confusion.display:main',
],
},
將build步驟參數的文件刪除干凈,再次build:
再次創建后仍然是這樣的問題,安裝好之后,使用confusion是正常的,但是使用confusionDraw.exe后就不能導入confusion庫了,在pycharm里面測試(其他項目下)也不能使用。經過不斷地測試,最后發現問題了,我們這里不能使用confusion.display:main
,在項目的display文件中,導入包的時候也一並將confusion刪除。即這里我進行了兩個操作:
- 將
from confusion.utils.Draw import ConfusionMatrixHeatMap as CH
修改為:from utils.Draw import ConfusionMatrixHeatMap as CH
; - 將entry_points中console_scripts的value修改為
display:main
。
再次刪除build產生的包,並再次安裝:
其他項目中使用此虛擬環境測試:
完!