PYTHONPATHคู่มือบรรจุภัณฑ์ Python อย่างเป็นทางการ
โมดูล ใน Python เป็นไฟล์เดียว (พร้อมส่วนขยาย .py ) ที่มีรหัส Python โดยทั่วไปจะประกอบด้วยคลาสฟังก์ชั่นและตัวแปรที่สามารถใช้งานได้ด้วยรหัส Python อื่น ๆ โมดูลใช้ในการจัดระเบียบรหัสเป็นหน่วยตรรกะและอำนวยความสะดวกในการใช้รหัสใหม่
ตัวอย่างเช่นพิจารณาโมดูลชื่อ math_operations.py ที่มีฟังก์ชั่นในการดำเนินการทางคณิตศาสตร์เช่นการเพิ่มการลบการคูณ ฯลฯ คุณสามารถนำเข้าและใช้ฟังก์ชั่นเหล่านี้ในสคริปต์ Python อื่น ๆ
# math_operations.py
def add ( x , y ):
return x + y
def subtract ( x , y ):
return x - y แพ็คเกจ ใน Python เป็นชุดของโมดูลที่จัดกลุ่มเข้าด้วยกันในไดเรกทอรี โดยทั่วไปแล้วแพ็คเกจจะถูกแทนด้วยไดเรกทอรีที่มีไฟล์ __init__.py (ซึ่งอาจว่างเปล่า) และโมดูล Python หนึ่งโมดูลหรือมากกว่า ไฟล์ __init__.py ระบุว่า Python ว่าไดเรกทอรีควรได้รับการปฏิบัติเป็นแพ็คเกจ
ตัวอย่างเช่นพิจารณาแพ็คเกจชื่อ my_package :
my_package/
├── __init__.py
├── module1.py
└── module2.py
ที่นี่ my_package เป็นแพ็คเกจที่มี module1.py และ module2.py ซึ่งสามารถนำเข้าได้โดยใช้สัญลักษณ์ dot ( my_package.module1 , my_package.module2 )
แพคเกจย่อย ใน Python เป็นแพ็คเกจซ้อนกันภายในแพ็คเกจอื่น ซึ่งหมายความว่าแพ็คเกจสามารถมีแพ็คเกจอื่น ๆ และโมดูล แพคเกจย่อยถูกสร้างขึ้นโดยการจัดระเบียบไดเรกทอรีและเพิ่มไฟล์ __init__.py อย่างเหมาะสมเพื่อกำหนดโครงสร้างแพ็คเกจ
ตัวอย่างเช่น:
my_parent_package/
├── __init__.py
└── my_sub_package/
├── __init__.py
├── module3.py
└── module4.py
ในโครงสร้างนี้ my_sub_package เป็นแพคเกจย่อยของ my_parent_package และสามารถมีโมดูลของตัวเอง ( module3.py , module4.py ) แพคเกจย่อยสามารถนำเข้าได้โดยใช้สัญลักษณ์ dot ( my_parent_package.my_sub_package.module3 )
แพ็คเกจการแจกจ่าย (หรือ การแจกจ่าย เพียงอย่างเดียว) ใน Python หมายถึงคอลเลกชันแพ็คของรหัส Python และทรัพยากรที่มีให้สำหรับการติดตั้ง โดยทั่วไปจะมีโมดูลแพ็คเกจไฟล์ข้อมูลไฟล์การกำหนดค่าและทรัพยากรอื่น ๆ ที่จำเป็นสำหรับวัตถุประสงค์เฉพาะ (เช่นไลบรารีหรือแอปพลิเคชัน)
แพ็คเกจการกระจายมักจะกระจายและติดตั้งโดยใช้ผู้จัดการแพ็คเกจ Python เช่น pip และสามารถอัปโหลดไปยังที่เก็บแพ็คเกจเช่น PYPI (ดัชนีแพ็คเกจ Python) เพื่อการกระจายและการติดตั้งที่ง่ายดายโดยนักพัฒนาอื่น ๆ
ตัวอย่างเช่นแพ็คเกจการแจกจ่ายที่เป็นที่นิยม ได้แก่ numpy , fast-api , pandas ฯลฯ ซึ่งติดตั้งโดยใช้ pip และให้ฟังก์ชันการทำงานที่สามารถใช้ในโครงการ Python
sdistsetup.pypython setup.py build sdist เพื่อสร้างการกระจายแหล่งที่มาpip install ./dist/<package_name>.tar.gz เพื่อติดตั้งแพ็คเกจpip list เพื่อดูว่ามีการติดตั้งแพ็คเกจหรือไม่ หากมีการเปลี่ยนแปลงในแพ็คเกจให้ใช้ pip install . ซึ่งจะสร้างและติดตั้งแพ็คเกจล่าสุดได้ทันที
หรือเพียงแค่ใช้แก้ไขได้เพื่อให้คุณไม่ต้องสร้างแพ็คเกจการเปลี่ยนแปลงใหม่ของ Evrerytime เสมอ:
pip install --editable . sdist สั้นสำหรับการแจกแจงแหล่งที่มาไฟล์ .tar ที่มีรหัสของเราที่เรียกว่า "SDIST" นั่นหมายความว่าแพ็คเกจการแจกจ่ายจะมีส่วนย่อยของซอร์สโค้ดของเราเท่านั้น
"การกระจายแหล่งที่มา" เป็นโฟลเดอร์ซิปที่มี ซอร์สโค้ด ของเรา
wheel การกระจายแหล่งที่มา ( sdist ) :
*.py ) ไฟล์การกำหนดค่าและสินทรัพย์ที่เกี่ยวข้องกับโครงการอื่น ๆpython setup.py sdist ล้อ ( bdist_wheel ) :
sdist.whlpython setup.py bdist_wheel การติดตั้งที่เร็วขึ้น :
*.whl ) โดยทั่วไปจะเร็วกว่าการติดตั้งจากการแจกแจงแหล่งที่มา ( *.tar.gz )ใช้งานง่ายสำหรับผู้ใช้ :
sdist และ bdist_wheelsdist และ bdist_wheel สำหรับแพ็คเกจ Python เพื่อรองรับกรณีการใช้งานและแพลตฟอร์มที่แตกต่างกันpython setup.py sdist bdist_wheelข้อกำหนดการรวบรวม :
น่าเสียดายที่การสร้างล้อสำหรับระบบปฏิบัติการ ทั้งหมด นั้นยากหากคุณมีขั้นตอนการรวบรวมดังนั้นผู้ดูแล OSS บางคนสร้างล้อสำหรับระบบปฏิบัติการเดียวเท่านั้น
pip จะดำเนินการ setup.py (หรือไฟล์เทียบเท่า) บนเครื่อง ของคุณ หลังจากดาวน์โหลด SDISTการสร้างล้ออาจต้องรวบรวมรหัส
gcc หากซอร์สโค้ดอยู่ใน C แต่ภาษาอื่น ๆ ต้องใช้คอมไพเลอร์ของตัวเอง ผู้ใช้จะต้องติดตั้งสิ่งเหล่านี้บนเครื่องบนเครื่องหรือ pip install ... จะล้มเหลว สิ่งนี้สามารถเกิดขึ้นได้เมื่อคุณติดตั้ง numpy , pandas , scipy , pytorch , tensorflow ฯลฯ setup.py อาจมีรหัสโดยพลการ นี่คือความไม่ปลอดภัยสูง setup.py อาจมีรหัสที่เป็นอันตราย
การจัดการการพึ่งพา :
gcc ฯลฯ ) เพื่อติดตั้งแพ็คเกจที่ต้องใช้การรวบรวมได้สำเร็จความกังวลด้านความปลอดภัย :
setup.py สำหรับการติดตั้งแพ็คเกจอาจไม่ปลอดภัยเนื่องจากจะดำเนินการรหัสโดยพลการwheelชื่อไฟล์ล้อถูกแบ่งออกเป็นชิ้นส่วนที่คั่นด้วยยัติภังค์:
{dist}-{version}(-{build})?-{python}-{abi}-{platform}.whl แต่ละส่วนใน {brackets} เป็นแท็กหรือส่วนประกอบของชื่อล้อที่มีความหมายบางอย่างเกี่ยวกับสิ่งที่ล้อมีและที่ล้อจะหรือจะไม่ทำงาน
ตัวอย่างเช่น: dist/packaging-0.0.0-py3-none-any.whl
packaging เป็นชื่อแพ็คเกจ0.0.0 คือหมายเลข Verisonpy3 หมายถึงมันสร้างสำหรับ Python3abi ABI หมายถึงอินเตอร์เฟสไบนารีแอปพลิเคชันany ที่มีอยู่สำหรับแพ็คเกจนี้จะสร้างขึ้นเพื่อทำงานบนแพลตฟอร์มใด ๆตัวอย่างอื่น ๆ :
cryptography-2.9.2-cp35-abi3-macosx_10_9_x86_64.whlchardet-3.0.4-py2.py3-none-any.whlPyYAML-5.3.1-cp38-cp38-win_amd64.whlnumpy-1.18.4-cp38-cp38-win32.whlscipy-1.4.1-cp36-cp36m-macosx_10_6_intel.whlเหตุผลนี้คือไฟล์ล้อมีรหัสไบนารีที่สมบูรณ์ล่วงหน้าซึ่งช่วยในการติดตั้งแพ็คเกจอย่างรวดเร็ว
การบำรุงรักษาแพ็คเกจ :
sdist และ bdist_wheel เพื่อเพิ่มความเข้ากันได้และความสะดวกในการใช้งานสำหรับผู้ใช้พิจารณาประสบการณ์ผู้ใช้ :
build เครื่องมือ CLI และ pyproject.toml"สร้างการพึ่งพา" เป็นสิ่งที่ต้องติดตั้งในระบบของคุณเพื่อสร้างแพ็คเกจการกระจายของคุณลงใน SDIST หรือล้อ
ตัวอย่างเช่นเราจำเป็นต้อง pip install wheel เพื่อเรียกใช้ python setup.py bdist_wheel ดังนั้น wheel จึงเป็นการพึ่งพาการสร้างสำหรับการสร้างล้อ
ไฟล์ setup.py อาจมีความซับซ้อน
คุณอาจต้อง pip install ... ไลบรารีภายนอกและนำเข้าไปยังไฟล์ setup.py ของคุณเพื่อรองรับกระบวนการสร้างที่ซับซ้อน
การบรรยายแสดง pytorch และ airflow เป็นตัวอย่างของแพ็คเกจที่มีไฟล์ setup.py ที่ซับซ้อน
อย่างใดคุณต้องสามารถจัดทำเอกสารการพึ่งพาการพึ่งพา นอก setup.py
หากพวกเขาได้รับการบันทึกไว้ในไฟล์ setup.py ... คุณจะไม่สามารถเรียกใช้ไฟล์ setup.py เพื่ออ่านการอ้างอิงที่บันทึกไว้ (เช่นถ้าพวกเขาระบุไว้ใน list ที่ใดที่หนึ่งในไฟล์)
นี่คือปัญหาดั้งเดิม pyproject.toml หมายถึงการแก้ปัญหา
# pyproject.toml
[ build-system ]
# Minimum requirements for the build system to execute.
requires = [ " setuptools>=62.0.0 " , " wheel " ] pyproject.toml อยู่ติดกับ setup.py ในแผนผังไฟล์
build CLI Tool ( pip install build ) เป็นโครงการพิเศษโดยหน่วยงาน Python Packaging Authority (PYPA) ซึ่ง
[build-system] ใน pyproject.toml ,pip install build
# both setup.py and pypproject.toml should be together, ideally in the root directory
# python -m build --sdist --wheel path/to/dir/with/setup.py/and/pyproject.toml
python -m build --sdist --wheel . setup.py ไปยังไฟล์ setup.cfgย้ายจาก
# setup.py
from pathlib import Path
from setuptools import find_packages , setup
import wheel
# Function to read the contents of README.md
def read_file ( filename : str ) -> str :
filepath = Path ( __file__ ). resolve (). parent / filename
with open ( filepath , encoding = "utf-8" ) as file :
return file . read ()
setup (
name = "packaging-demo" ,
version = "0.0.0" ,
packages = find_packages (),
# package meta-data
author = "Amit Vikram Raj" ,
author_email = "[email protected]" ,
description = "Demo for Python Packaging" ,
license = "MIT" ,
# Set the long description from README.md
long_description = read_file ( "README.md" ),
long_description_content_type = "text/markdown" ,
# install requires: libraries that are needed for the package to work
install_requires = [
"numpy" , # our package depends on numpy
],
# setup requires: the libraries that are needed to setup/build
# the package distribution
# setup_requires=[
# "wheel", # to build the binary distribution we need wheel package
# ],
)ถึง
# setup.py
from setuptools import setup
# Now setup.py takes it's configurations from setup.cfg file
setup () # setup.cfg
[metadata]
name = packaging-demo
version = attr: packaging_demo.VERSION
author = Amit Vikram Raj
author_email = [email protected]
description = Demo for Python Packaging
long_description = file: README.md
keywords = one, two
license = MIT
classifiers =
Framework :: Django
Programming Language :: Python :: 3
[options]
zip_safe = False
include_package_data = True
# same as find_packages() in setup()
packages = find:
python_requires = >=3.8
install_requires =
numpy
importlib-metadata ; python_version<"3.10"การตั้งค่า addtional จะถูกส่งผ่านไปยังไฟล์
pyproject.tomlที่นี่เราได้ระบุbuild-systemคล้ายกับsetup_requiresในsetup.py
# pyproject.toml
[ build-system ]
# Minimum requirements for the build system to execute
requires = [ " setuptools " , " wheel " , " numpy<1.24.3 " ]
# Adding ruff.toml to pyproject.toml
[ tool . ruff ]
line-length = 99
[ tool . ruff . lint ]
# 1. Enable flake8-bugbear (`B`) rules, in addition to the defaults.
select = [ " E " , " F " , " B " , " ERA " ]
# 2. Avoid enforcing line-length violations (`E501`)
ignore = [ " E501 " ]
# 3. Avoid trying to fix flake8-bugbear (`B`) violations.
unfixable = [ " B " ]
# 4. Ignore `E402` (import violations) in all `__init__.py` files, and in select subdirectories.
[ tool . ruff . lint . per-file-ignores ]
"__init__.py" = [ " E402 " ]
"**/{tests,docs,tools}/*" = [ " E402 " ]
# copying isort configurations from .isort.cfg to pyproject.toml
[ tool . isort ]
profile = " black "
multi_line_output = " VERTICAL_HANGING_INDENT "
force_grid_wrap = 2
line_length = 99
# copying balck config from .black.toml to pyproject.toml
[ tool . black ]
line-length = 99
exclude = " .venv "
# copying flake8 config from .flake8 to pyproject.toml
[ tool . flake8 ]
docstring-convention = " all "
extend-ignore = [ " D107 " , " D212 " , " E501 " , " W503 " , " W605 " , " D203 " , " D100 " ,
" E305 " , " E701 " , " DAR101 " , " DAR201 " ]
exclude = [ " .venv " ]
max-line-length = 99
# radon
radon-max-cc = 10
# copying pylint config from .pylintrc to pyproject.toml
[ tool . pylint . "messages control" ]
disable = [
" line-too-long " ,
" trailing-whitespace " ,
" missing-function-docstring " ,
" consider-using-f-string " ,
" import-error " ,
" too-few-public-methods " ,
" redefined-outer-name " ,
] เราได้รับการรักษา setup.py เป็นไฟล์กำหนดค่าที่ได้รับการยกย่องไม่ใช่การใช้ประโยชน์จากความจริงที่ว่ามันเป็นไฟล์ Python โดยการเพิ่มตรรกะลงไป
นี่เป็นเรื่องธรรมดามากกว่าไม่ นอกจากนี้ยังมีการเปลี่ยนแปลงทั่วไปจากการใช้ Python สำหรับไฟล์ config เนื่องจากการทำเช่นนั้นเพิ่มความซับซ้อนให้กับ การใช้ ไฟล์ config (เช่นต้องติดตั้งไลบรารีเพื่อเรียกใช้ไฟล์ config)
setup.cfg เป็นไฟล์ Companion to setup.py ที่ช่วยให้เราสามารถกำหนดค่าแพ็คเกจของเราในไฟล์ข้อความแบบคงที่ - โดยเฉพาะไฟล์รูปแบบ INI
ค่าใด ๆ ที่เราไม่ผ่านโดยตรงเป็นอาร์กิวเมนต์ในการตั้งค่า () จะถูกค้นหาโดยการตั้งค่า () การเรียกใช้ในไฟล์ setup.cfg ซึ่งหมายถึงการนั่งติดกับ setup.py ในแผนผังไฟล์หากใช้
ตอนนี้เรากำลังสะสมไฟล์จำนวนมาก!
setup.pysetup.cfgpyproject.tomlREADME.md.pylintrc , .flake8 , .blackrc , ruff.toml , .mypy , pre-commit-config.yaml ฯลฯCHANGELOG หรือ CHANGELOG.mdVERSION หรือ version.txt ปรากฎว่าเกือบทั้งหมดของไฟล์เหล่านี้สามารถแทนที่ด้วย pyproject.toml เกือบทุกเครื่องมือที่มีคุณภาพผ้าสำลี / รหัสสนับสนุนการแยกวิเคราะห์ส่วนที่เรียกว่า [tool.<name>] เช่น [tool.black] ส่วนของ pyproject.toml เพื่ออ่านการกำหนดค่า!
เอกสารของเครื่องมือแต่ละตัวควรบอกวิธีการทำสิ่งนี้ให้สำเร็จ
ข้างต้นแสดงเป็น pyproject.toml พร้อมการกำหนดค่าสำหรับเครื่องมือผ้าสำลีที่เราใช้ในหลักสูตร
สามารถ
setup.cfgและsetup.pyได้เช่นกันหรือไม่?
setup.cfg เป็น pyproject.tomlจาก
setup.cfg
# setup.cfg
[metadata]
name = packaging-demo
version = attr: packaging_demo.VERSION
author = Amit Vikram Raj
author_email = [email protected]
description = Demo for Python Packaging
long_description = file: README.md
keywords = one, two
license = MIT
classifiers =
Programming Language :: Python :: 3
[options]
zip_safe = False
include_package_data = True
# same as find_packages() in setup()
packages = find:
python_requires = >=3.8
install_requires =
numpy
importlib-metadata ; python_version<"3.10"ถึง
# pyproject.toml
[ build-system ]
# Minimum requirements for the build system to execute
requires = [ " setuptools>=61.0.0 " , " wheel " ]
# Adding these from setup.cfg in pyproject.toml file
[ project ]
name = " packaging-demo "
authors = [{ name = " Amit Vikram Raj " , email = " [email protected] " }]
description = " Demo for Python Packaging "
readme = " README.md "
requires-python = " >=3.8 "
keywords = [ " one " , " two " ]
license = { text = " MIT " }
classifiers = [ " Programming Language :: Python :: 3 " ]
dependencies = [ " numpy " , ' importlib-metadata; python_version<"3.10" ' ]
dynamic = [ " version " ]
# version = "0.0.3"
# https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#dynamic-metadata
[ tool . setuptools . dynamic ]
# every while making changes in package, you can change the verison in one of these files
# version = {attr = "packaging_demo.VERSION"} # version read by 'packaging_demo/__init__.py' file
version = { file = [ " version.txt " ]} # version read by 'version.txt' file in root folder
python -m build --sdist --wheel .- ทำงานได้อย่างสมบูรณ์แบบเราได้กำจัดไฟล์กำหนดค่าอื่น (setup.cfg)
setup.py ด้วย build-backend PEP 517 เพิ่มอาร์กิวเมนต์ build-backend ให้กับ pyproject.toml เช่น So:
[ build-system ]
# Defined by PEP 518:
requires = [ " flit " ]
# Defined by this PEP:
build-backend = " flit.api:main " # The above toml config is equivalent to
import flit . api
backend = flit . api . main build-backend กำหนดจุดเข้าใช้งาน (โมดูล Python ที่ดำเนินการได้ในกรณีนี้) ที่ build CLI ใช้ในการทำงานของการแยกวิเคราะห์ pyproject.toml และสร้างล้อและ sdist
ซึ่งหมายความว่า คุณ สามารถใช้แบ็กเอนด์บิวด์ของคุณเองได้ในวันนี้โดยการเขียนโปรแกรมที่ทำเช่นนั้นและคุณสามารถใช้งานได้โดยการเพิ่มแพ็คเกจของคุณให้ requires = [...] และระบุจุดเข้าร่วมใน build-backend = ...
หากคุณไม่ได้ระบุ build-backend ใน pyproject.toml setuptools จะถูกสันนิษฐานและแพ็คเกจจะได้รับ bulit อย่างดี
setup.py และเรียกใช้ python -m build --sdist --wheel . มันทำงานได้อย่างสมบูรณ์แบบโดยไม่ต้องใช้ค่าเริ่มต้นของ build-system ถูกตั้งค่าเป็น build-backend = "setuptools.build_meta" ใน build CLI ซึ่งสร้างแพ็คเกจของเรา แต่คุณยังสามารถประกาศ setuptools อย่างชัดเจนว่าเป็นแบ็กเอนด์งานสร้างของคุณเช่นนี้
# pyproject.toml
...
[ build-system ]
requires = [ " setuptools>=61.0.0 " , " wheel " ]
build-backend = " setuptools.build_meta "
... โดยทั่วไปแล้วการสร้างแบ็กเอนด์จะขยายไฟล์ pyproject.toml ด้วยตัวเลือกการกำหนดค่าของตัวเอง ตัวอย่างเช่น,
# pyproject.toml
...
[ tool . setuptools . package-data ]
package_demo = [ " *.json " ]
[ tool . setuptools . dynamic ]
version = { file = " version.txt " }
long_description = { file = " README.md " }
... หากคุณเลือกที่จะใช้ setuptools ในโครงการของคุณคุณสามารถเพิ่มส่วนเหล่านี้ลงใน pyproject.toml คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ในเอกสาร setuptools
บ่อยครั้งที่มีประโยชน์ในการรวมไฟล์ที่ไม่ใช่ python เช่นไฟล์ข้อมูลหรือไฟล์ไบนารีภายในแพ็คเกจของคุณเนื่องจากรหัส Python ของคุณมักขึ้นอยู่กับไฟล์ที่ไม่ใช่ Python เหล่านี้
จากนั้นเราก็เห็นว่าหากเราจะรวมไฟล์เหล่านั้นเราต้องให้ไฟล์เหล่านั้นจบลงในโฟลเดอร์แพ็คเกจของเราเพราะเป็นโฟลเดอร์แพ็คเกจของเราที่จบลงในสภาพแวดล้อมเสมือนจริงของผู้ใช้เมื่อติดตั้ง
นอกจากนี้เรายังเห็นว่าโดยค่าเริ่มต้นไฟล์ที่ไม่ใช่ Python ทั้งหมดจะไม่ทำให้เป็นโฟลเดอร์สภาพแวดล้อมเสมือนจริงสุดท้าย นั่นคืออย่าทำให้มันเป็นโฟลเดอร์แพ็คเกจของเราในระหว่างขั้นตอนการสร้าง
ดังนั้นเราจะตรวจสอบให้แน่ใจได้อย่างไรว่าไฟล์เหล่านี้จบลงด้วยการสร้างพวงมาลัย/dist ของแพ็คเกจของเรา ตัวอย่างเช่นที่นี่เราสาธิตไฟล์ cities.json ที่เราต้องการในแพ็คเกจของเราเนื่องจากไฟล์ states_info.py ใช้
setuptoolsDocs อย่างเป็นทางการสำหรับการสนับสนุนข้อมูล
# pyprject.toml
[ tool . setuptools ]
# ...
# By default, include-package-data is true in pyproject.toml, so you do
# NOT have to specify this line.
include-package-data = true ดังนั้น setuptools โดยค่าเริ่มต้นมีสิ่งนี้ include-package-data ที่ตั้งค่าเป็น true ตามที่แสดงในเอกสารอย่างเป็นทางการ แต่เราจำเป็นต้องสร้างไฟล์พิเศษ MANIFEST.in และระบุข้อมูลที่เราต้องการ inculde ในแพ็คเกจของเราที่รูท Dir
IMP: นำเข้าโฟลเดอร์ทั้งหมดในไดเรกทอรีแพ็คเกจควรมี
__init__.py__init__.pyที่ใส่ไดเรกทอรีข้อมูลซึ่งเราต้องการรวมเพราะfind_packages()กระบวนการ recusrive ที่ setuptools จะไม่เข้าสู่;
# MANIFEST.in
include packaging_demo/*.json
include packaging_demo/my_folder/*.json
OR
Recursive include all json files in the package directory
recursive-include packaging_demo/ *.json
เอกสารเกี่ยวกับการกำหนดค่า manifest.in ไฟล์
MANIFEST.in ไฟล์ จากเอกสาร setuptools เราสามารถเพิ่มสิ่งนี้ในไฟล์ pyproject.toml ของเรา:
# this is by default true so no need to explicitly add it
# but as mentioned in the docs, it is false for other methods like setup.py or setup.cfg
[ tool . setuptools ]
include-package-data = true
# add the data here, it's finding the files recursively
[ tool . setuptools . package-data ]
package_demo = [ " *.json " ]build-backend อื่น ๆ นอกเหนือจาก setuptools นอกเหนือจาก setuptools แล้วเราสามารถใช้ระบบแบ็กเอนด์ Build เหล่านี้ จุดที่ควรทราบคือเมื่อใช้ระบบอื่น ๆ pyproject.toml cofiguration ควรติดตาม standerds ของพวกเขา
ฟัก
[ build-system ]
requires = [ " hatchling " ]
build-backend = " hatchling.build "บทกวี
[ build-system ]
requires = [ " poetry-core>=1.0.0 " ]
build-backend = " poetry.core.masonry.api " การบันทึกเวอร์ชันที่แน่นอนของการพึ่งพาของเราและการพึ่งพาของพวกเขาและอื่น ๆ
ขอแนะนำให้มีจำนวนการพึ่งพาที่เกี่ยวข้องกับแพ็คเกจของเราน้อยที่สุดเท่าที่จะเป็นไปได้เนื่องจากอาจนำไปสู่การพึ่งพานรกหรือความขัดแย้งในการพึ่งพากับแพ็คเกจอื่น ๆ ตามที่อธิบายไว้ในการบรรยาย
ยิ่งต้นไม้พึ่งพามีความซับซ้อนมากขึ้นโอกาสที่จะขัดแย้งกับห้องสมุดรุ่นอื่น ๆ ในอนาคต
การวิเคราะห์กราฟการพึ่งพาโดย Eric
การรักษาเวอร์ชันการพึ่งพาและรุ่น Python ที่ตรึงไว้นั้นเป็นไปได้สำหรับการแก้ไขปัญหา:
pip freeze > requirements.txt pip install pipdeptree graphviz
sudo apt-get install graphviz
# generate the dependency graph
pipdeptree -p packaging-demo --graph-output png > dependency-graph.png[ project . optional-dependencies ]
dev = [ " ruff " , " mypy " , " black " ] # installing our package with optional dependencies
pip install ' .[dev] ' [ project . optional-dependencies ]
# for developement
dev = [ " ruff " , " mypy " , " black " ]
# plugin based architecture
colors = [ " rich " ] # plugin based installation
pip install ' .[colors] '
# here we demo with rich library, if user wants the output to be
# colorized then they can install our package like this.
# we can add multiple optional dependencies like:
pip install ' .[colors, dev] ' [ project . optional-dependencies ]
# for developement
dev = [ " ruff " , " mypy " , " black " ]
# plugin based architecture
colors = [ " rich " ]
# install all dependencies
all = [ " packaging-demo[dev, colors] " ] # Installing all dependencies all at once
pip install ' .[all] ' เราสามารถใช้ SNYK เพื่อตรวจสอบว่ามีความเสถียรได้รับการสนับสนุนอย่างดีหากมีปัญหาด้านความปลอดภัย ฯลฯ สำหรับการอ้างอิงที่เราจะใช้สำหรับแพ็คเกจของเราแล้วตัดสินใจใช้ในโครงการของเรา
เพื่อป้องกันแพ็คเกจของเราไปยัง PYPI [ดัชนีบรรจุภัณฑ์ Python] ตามที่ระบุไว้ในคู่มืออย่างเป็นทางการเราใช้เครื่องมือ twine CLI
pip install twine
twine upload --helpสร้างโทเค็น API สำหรับการทดสอบ PYPI หรือ PYPI Prod
สร้างแพ็คเกจ Python ของคุณ: python -m build --sdist --wheel "${PACKAGE_DIR}" ที่นี่เรากำลังสร้างทั้ง sdist และ wheel ตามที่แนะนำ
เรียกใช้เครื่องมือ Twine: twine upload --repository testpypi ./dist/* การอัปโหลดไปยัง Test-Pypi
CMake และ Makefile
sudo apt-get install makeไฟล์
justfile
คนขี้เกียจ
คนกิน
$ rightarrow $ QA/staging$ rightarrow $ แยง



# .github/workflows/publish.yaml
name : Build, Test, and Publish
# triggers: whenever there is new changes pulled/pushed on this
# repo under given conditions, run the below jobs
on :
pull_request :
types : [opened, synchronize]
push :
branches :
- main
# Manually trigger a workflow
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch
workflow_dispatch :
jobs :
build-test-and-publish :
runs-on : ubuntu-latest
steps :
# github actions checksout, clones our repo, and checks out the branch we're working in
- uses : actions/checkout@v3
with :
# Number of commits to fetch. 0 indicates all history for all branches and tags
# fetching all tags so to aviod duplicate version tagging in 'Tag with the Release Version'
fetch-depth : 0
- name : Set up Python 3.8
uses : actions/setup-python@v3
with :
python-version : 3.8
# tagging the release version to avoid duplicate releases
- name : Tag with the Release Version
run : |
git tag $(cat version.txt)
- name : Install Python Dependencies
run : |
/bin/bash -x run.sh install
- name : Lint, Format, and Other Static Code Quality Check
run : |
/bin/bash -x run.sh lint:ci
- name : Build Python Package
run : |
/bin/bash -x run.sh build
- name : Publish to Test PyPI
# setting -x in below publish:test will not leak any secrets as they are masked in github
if : ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
run : |
/bin/bash -x run.sh publish:test
env :
TEST_PYPI_TOKEN : ${{ secrets.TEST_PYPI_TOKEN }}
- name : Publish to Prod PyPI
if : ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
run : |
/bin/bash -x run.sh publish:prod
env :
PROD_PYPI_TOKEN : ${{ secrets.PROD_PYPI_TOKEN }}
- name : Push Tags
if : ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
run : |
git push origin --tagsข้อกำหนดการล็อค
การแคชการพึ่งพา
เมื่อใดก็ตามที่การกระทำของ GitHub ถูกดำเนินการใน GitHub CI ทุกครั้งที่มันทำงานบนภาชนะบรรจุสด ดังนั้นทุกครั้งที่เราต้องดาวน์โหลดและติดตั้งการพึ่งพาใหม่จาก PIP ซ้ำแล้วซ้ำอีก ซึ่งไม่ดีเพราะมันไม่มีประสิทธิภาพและทำให้เวิร์กโฟลว์ของเราช้าลง
ดังนั้นเราจึงต้องการติดตั้งการพึ่งพาทั้งหมดเมื่อเวิร์กโฟลว์ทำงานก่อนและใช้มันทุกครั้งที่มีการทำงานของ worflow ใหม่
การกระทำของ GitHub ให้ฟังก์ชั่นนี้โดยการแคชการพึ่งพามันเก็บการพึ่งพาที่ติดตั้งไว้ ( ~/.cache/pip ) และดาวน์โหลดทุกครั้งที่เวิร์กโฟลว์ใหม่ทำงาน เอกสาร
- uses : actions/cache@v3
with :
path : ~/.cache/pip
key : ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys : |
${{ runner.os }}-pip-setup-python steps :
- uses : actions/checkout@v4
- uses : actions/setup-python@v5
with :
python-version : ' 3.9 '
cache : ' pip ' # caching pip dependencies
- run : pip install -r requirements.txtการทำให้ขนานกัน
# See .github/workflows/publish.yaml
jobs :
check-verison-txt :
...
lint-format-and-static-code-checks :
....
build-wheel-and-sdist :
...
publish :
needs :
- check-verison-txt
- lint-format-and-static-code-checks
- build-wheel-and-sdist
...