วิธีมาตรฐานในการฝังเวอร์ชันลงในแพคเกจหลาม?


264

มีวิธีมาตรฐานในการเชื่อมโยงสตริงเวอร์ชันกับแพคเกจหลามในแบบที่ฉันสามารถทำต่อไปนี้?

import foo
print foo.version

ฉันคิดว่ามีวิธีการในการดึงข้อมูลนั้นโดยไม่มีการเข้ารหัสพิเศษเพิ่มเติมเนื่องจากมีการระบุสตริงย่อย / สายหลักไว้setup.pyแล้ว โซลูชั่นทางเลือกที่ผมพบว่าจะมีimport __version__ในของฉันfoo/__init__.pyและจากนั้นได้สร้างขึ้นโดย__version__.pysetup.py


7
FYI มีภาพรวมที่ดีมากที่: packaging.python.org/en/latest/…
ionelmc

1
เวอร์ชันของแพคเกจที่ติดตั้งสามารถเรียกคืนได้จากข้อมูลเมตาด้วยsetuptoolsดังนั้นในหลายกรณีการวางเฉพาะรุ่นsetup.pyก็เพียงพอแล้ว ดูคำถามนี้
saaj

2
FYI, โดยทั่วไปมี5 รูปแบบทั่วไปเพื่อรักษาแหล่งความจริงเดียว (ทั้งการตั้งค่าและเวลาทำงาน) สำหรับหมายเลขรุ่น
KF Lin

@ionelmc ธ เอกสารรายการ7 ตัวเลือกที่แตกต่างกันสำหรับเดียว นั่นไม่ขัดแย้งกับแนวคิดของ " แหล่งเดียวของความจริง " หรือไม่?
Stevoisiak

@StevenVascellaro ไม่แน่ใจว่าสิ่งที่คุณถาม มีหลายวิธีในรายการเนื่องจากคู่มือบรรจุภัณฑ์ไม่ต้องการแสดงความคิดเห็น
ionelmc

คำตอบ:


136

ไม่ได้โดยตรงคำตอบของคำถามของคุณ แต่คุณควรพิจารณาตั้งชื่อมันไม่ได้__version__version

นี่เป็นมาตรฐานเสมือน โมดูลจำนวนมากในการใช้งานห้องสมุดมาตรฐาน__version__และนี้ก็ยังใช้ในจำนวนมากของโมดูลของบุคคลที่ 3 จึงเป็นเสมือนมาตรฐาน

โดยปกติแล้ว__version__จะเป็นสตริง แต่บางครั้งก็เป็นแบบลอยหรือแบบทูเปิล

แก้ไข: ดังที่ S.Lott (ขอขอบคุณ!), PEP 8บอกว่าชัดเจน:

ชื่อโมดูลระดับตัวทำลาย

โมดูล "dunders" ระดับ (เช่นชื่อที่มีเครื่องหมายนำหน้าสองอันและขีดล่างสองอัน) เช่น__all__,__author__ , __version__ฯลฯ ควรอยู่หลัง docstring โมดูล แต่ก่อนที่งบนำเข้าใด ๆ ยกเว้นจาก__future__การนำเข้า

คุณควรตรวจสอบให้แน่ใจว่าหมายเลขเวอร์ชันเป็นไปตามรูปแบบที่อธิบายไว้ในPEP 440 ( PEP 386เวอร์ชันก่อนหน้าของมาตรฐานนี้)


9
ควรเป็นสตริงและมีversion_infoสำหรับเวอร์ชัน tuple
James Antill

James: ทำไมเป็น__version_info__พิเศษ (ซึ่ง "ประดิษฐ์" เครื่องหมายขีดเส้นใต้คู่ของคุณเอง) [เมื่อเจมส์แสดงความคิดเห็นขีดเส้นใต้ไม่ได้ทำอะไรเลยในความคิดเห็นตอนนี้พวกเขาบ่งบอกถึงความสำคัญดังนั้นเจมส์จึงเขียน__version_info__ด้วยเช่นกัน --- ed.]

คุณสามารถเห็นบางสิ่งเกี่ยวกับเวอร์ชันที่ควรพูดได้ที่packages.python.org/distribute/ ...... หน้านั้นเกี่ยวกับการแจกจ่าย แต่ความหมายของหมายเลขเวอร์ชันกำลังกลายเป็นมาตรฐานจริง
sienkiew

2
ขวา. ดูเหมือนว่า PEPs เหล่านี้จะขัดแย้งกัน PEP 8 บอกว่า "ถ้า" และ "crud" ดังนั้นมันจึงไม่สนับสนุนการใช้คำหลัก VCS นอกจากนี้หากคุณเปลี่ยนไปใช้ VCS อื่นคุณจะสูญเสียข้อมูลการแก้ไข ดังนั้นฉันขอแนะนำให้ใช้ข้อมูลเวอร์ชันที่สอดคล้องกับ PEP 386/440 ที่ฝังอยู่ในไฟล์ต้นฉบับอย่างน้อยที่สุดสำหรับโครงการขนาดใหญ่
oefe

2
คุณจะวางเวอร์ชั่นนั้นไว้ที่ไหน พิจารณาว่าเป็นรุ่นที่ได้รับการยอมรับฉันชอบที่จะดูข้อมูลเพิ่มเติมที่นี่
darkgaze

120

ฉันใช้_version.pyไฟล์เดียวเป็น "ครั้งเดียวสถานที่ cannonical" เพื่อเก็บข้อมูลรุ่น:

  1. มันมี__version__คุณสมบัติ

  2. มันให้รุ่นข้อมูลเมตามาตรฐาน ดังนั้นจะถูกตรวจพบโดยpkg_resourcesหรือเครื่องมืออื่น ๆ ที่แยกวิเคราะห์ข้อมูลเมตาแพคเกจ (EGG-INFO และ / หรือ PKG-INFO, PEP 0345)

  3. ไม่นำเข้าแพ็คเกจของคุณ (หรือสิ่งอื่นใด) เมื่อสร้างแพ็คเกจของคุณซึ่งอาจทำให้เกิดปัญหาในบางสถานการณ์ (ดูความคิดเห็นด้านล่างเกี่ยวกับปัญหาที่อาจทำให้เกิด)

  4. มีเพียงที่เดียวเท่านั้นที่หมายเลขรุ่นถูกเขียนลงดังนั้นจึงมีเพียงสถานที่เดียวที่จะเปลี่ยนเมื่อหมายเลขเวอร์ชันเปลี่ยนแปลงและมีโอกาสน้อยกว่าในรุ่นที่ไม่สอดคล้องกัน

นี่คือวิธีการทำงาน: ความ "หนึ่งในสถานที่ที่เป็นที่ยอมรับ" ในการจัดเก็บหมายเลขรุ่นเป็นไฟล์ .py ชื่อ "_version.py" myniftyapp/_version.pyซึ่งอยู่ในแพคเกจหลามของคุณตัวอย่างเช่นใน ไฟล์นี้เป็นโมดูล Python แต่ setup.py ของคุณไม่ได้นำเข้า! (นั่นจะทำให้ฟีเจอร์ที่ 3) setup setup ของคุณรู้ว่าเนื้อหาของไฟล์นี้นั้นง่ายมาก

__version__ = "3.6.5"

ดังนั้น setup.py ของคุณจะเปิดไฟล์และแยกวิเคราะห์ด้วยรหัสดังนี้

import re
VERSIONFILE="myniftyapp/_version.py"
verstrline = open(VERSIONFILE, "rt").read()
VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
mo = re.search(VSRE, verstrline, re.M)
if mo:
    verstr = mo.group(1)
else:
    raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))

จากนั้น setup.py ของคุณจะส่งผ่านสตริงนั้นเป็นค่าของอาร์กิวเมนต์ "version" setup()ตามฟีเจอร์ที่น่าพอใจ 2

เพื่อให้เป็นไปตามคุณสมบัติที่ 1 คุณสามารถมีแพ็คเกจของคุณ (ในเวลาทำงานไม่ใช่เวลาติดตั้ง!) นำเข้าไฟล์ _version จากmyniftyapp/__init__.pyนี้:

from _version import __version__

นี่คือตัวอย่างของเทคนิคนี้ที่ฉันใช้มานานหลายปี

รหัสในตัวอย่างนั้นซับซ้อนกว่าเล็กน้อย แต่ตัวอย่างที่เรียบง่ายที่ฉันเขียนลงในความคิดเห็นนี้ควรเป็นการใช้งานที่สมบูรณ์

นี่คือตัวอย่างรหัสการนำเข้าเวอร์ชันโค้ดตัวอย่างของการนำเข้ารุ่น

หากคุณเห็นอะไรผิดปกติกับวิธีนี้โปรดแจ้งให้เราทราบ


8
คุณช่วยอธิบายปัญหาที่กระตุ้น # 3 ได้ไหม Glyph กล่าวว่ามีบางอย่างเกี่ยวข้องกับ "setuptools ชอบที่จะแกล้งทำเป็นว่ารหัสของคุณไม่ได้อยู่ในระบบเมื่อ setup.py ของคุณทำงาน" แต่รายละเอียดจะช่วยโน้มน้าวฉันและผู้อื่น
Ivan Kozik

2
@Iva ทีนี้เครื่องมือควรจะทำยังไงกับมัน? มันไม่สามารถ (ใน setuptools / pip / virtualenv ระบบการทำงานของวันนี้) ได้รู้ว่าสิ่ง deps อยู่setup.pyจนกว่าจะมีการประเมินผลของคุณ นอกจากนี้ถ้ามันพยายามทำแบบเต็มความลึกก่อนและทำทุกอย่างออกมาก่อนที่มันจะทำแบบนี้มันจะติดถ้ามันมีรูปวงกลม แต่ถ้ามันพยายามที่จะสร้างแพคเกจนี้ก่อนที่จะติดตั้งการพึ่งพาจากนั้นถ้าคุณนำเข้าแพคเกจของคุณจากนั้นคุณsetup.pyจะไม่สามารถนำเข้า deps หรือรุ่นที่เหมาะสมของ dep ของมัน
Zooko

3
คุณสามารถเขียนไฟล์ "version.py" จาก "setup.py" แทนการแยกวิเคราะห์ได้หรือไม่ ดูเหมือนง่ายกว่า
Jonathan Hartley

3
Jonathan Hartley: ฉันยอมรับว่ามันจะง่ายกว่าเล็กน้อยสำหรับ "setup.py" ของคุณในการเขียนไฟล์ "version.py" แทนที่จะแยกวิเคราะห์ แต่จะเปิดหน้าต่างขึ้นมาเพื่อความไม่สอดคล้องกันเมื่อคุณแก้ไข setup.py เพื่อให้เป็นเวอร์ชั่นใหม่ แต่ยังไม่ได้ดำเนินการ setup.py เพื่ออัปเดตไฟล์ version.py อีกเหตุผลหนึ่งที่มีรุ่นมาตรฐานคือไฟล์เล็ก ๆ แยกต่างหากคือทำให้เครื่องมืออื่น ๆเช่นเครื่องมือที่อ่านสถานะการควบคุมการแก้ไขของคุณง่ายขึ้นเพื่อเขียนไฟล์เวอร์ชัน
Zooko

3
วิธีที่คล้ายกันคือexecfile("myniftyapp/_version.py")จากภายใน setup.py แทนที่จะพยายามแยกวิเคราะห์รหัสเวอร์ชั่นด้วยตนเอง แนะนำในstackoverflow.com/a/2073599/647002 - การอภิปรายอาจมีประโยชน์เช่นกัน
medmunds

97

เขียนใหม่ 2017-05

หลังจากใช้เวลามากกว่าสิบปีในการเขียนรหัส Python และจัดการแพ็คเกจต่างๆฉันได้ข้อสรุปว่า DIY อาจไม่ใช่วิธีที่ดีที่สุด

ฉันเริ่มใช้pbrแพ็คเกจเพื่อจัดการกับการกำหนดเวอร์ชันในแพ็คเกจของฉัน หากคุณใช้คอมไพล์เป็น SCM ของคุณสิ่งนี้จะเข้ากับเวิร์กโฟลว์ของคุณได้อย่างวิเศษประหยัดสัปดาห์ของการทำงาน (คุณจะประหลาดใจกับความซับซ้อนของปัญหา)

ณ วันนี้pbr ได้รับการจัดอันดับเป็น # 11 แพ็คเกจ python ที่ใช้มากที่สุดและถึงระดับนี้ไม่ได้มีลูกเล่นสกปรก: มีเพียงอันเดียวเท่านั้น: แก้ไขปัญหาบรรจุภัณฑ์ทั่วไปด้วยวิธีที่ง่ายมาก

pbr สามารถทำภาระการบำรุงรักษาแพ็คเกจได้มากขึ้นไม่ จำกัด เฉพาะรุ่น แต่ไม่ได้บังคับให้คุณใช้ประโยชน์ทั้งหมด

ดังนั้นเพื่อให้คุณมีความคิดเกี่ยวกับวิธีการที่จะมีลักษณะที่จะนำมาใช้ในหนึ่ง PBR กระทำมีลักษณะบรรจุภัณฑ์ swiching เพื่อ PBR

อาจเป็นไปได้ว่าคุณจะสังเกตเห็นว่ารุ่นนี้ไม่ได้เก็บไว้ในที่เก็บ PBR ตรวจจับได้จากกิ่ง Git และแท็ก

ไม่ต้องกังวลเกี่ยวกับสิ่งที่เกิดขึ้นเมื่อคุณไม่มีที่เก็บ git เพราะ pbr "คอมไพล์" และแคชเวอร์ชันเมื่อคุณทำแพ็กเกจหรือติดตั้งแอปพลิเคชันดังนั้นจึงไม่มีการพึ่งพารันไทม์บน git

วิธีการแก้ปัญหาเก่า

นี่เป็นทางออกที่ดีที่สุดที่ฉันเคยเห็นและอธิบายว่าทำไม:

ภายในyourpackage/version.py:

# Store the version here so:
# 1) we don't load dependencies by storing it in __init__.py
# 2) we can import it in setup.py for the same reason
# 3) we can import it into your module module
__version__ = '0.12'

ภายในyourpackage/__init__.py:

from .version import __version__

ภายในsetup.py:

exec(open('yourpackage/version.py').read())
setup(
    ...
    version=__version__,
    ...

หากคุณรู้จักวิธีการอื่นที่ดีกว่าโปรดแจ้งให้เราทราบ


12
เอ่อไม่มี execfile () ไม่มีอยู่ใน Python 3 ดังนั้นจะเป็นการดีกว่าถ้าใช้ exec (open (). read ())
Christophe Vu-Brugier

4
ทำไมถึงไม่from .version import __version__อยู่ใน setup.py ด้วย?
Aprillion

4
@Aprillion เนื่องจากแพคเกจไม่ได้โหลดเมื่อsetup.pyใช้งาน - ลองคุณจะได้รับข้อผิดพลาด (หรืออย่างน้อยฉันก็ :-))
darthbith

3
ลิงก์ไปยัง pbr ส่งผลให้เกตเวย์ไม่ดี
ลดราคา

4
pbrไม่ต้องสงสัยเลยว่าเป็นเครื่องมือที่ยอดเยี่ยม แต่คุณไม่สามารถตอบคำถามได้ คุณสามารถเข้าถึงเวอร์ชันปัจจุบันหรือแพ็คเกจที่ติดตั้งผ่านbprได้อย่างไร
nad2000

29

ตามPEP 396 ที่เลื่อนออกไป(หมายเลขเวอร์ชันของโมดูล)มีวิธีเสนอให้ทำเช่นนี้ มันอธิบายด้วยเหตุผลมาตรฐาน (ทางเลือกยอมรับ) สำหรับโมดูลที่จะปฏิบัติตาม นี่คือตัวอย่าง:

3) เมื่อโมดูล (หรือแพ็กเกจ) มีหมายเลขเวอร์ชันเวอร์ชัน SHOULD จะมีอยู่ในแอ__version__ททริบิวต์

4) สำหรับโมดูลที่อยู่ภายในแพ็คเกจเนมสเปซโมดูล SHOULD จะมีแอ__version__ททริบิวต์ แพ็คเกจเนมสเปซเองไม่ควรมี__version__แอตทริบิวต์ของตัวเอง

5) __version__ค่าของแอตทริบิวต์ควรเป็นสตริง


13
PEP นั้นไม่ได้รับการยอมรับ / เป็นมาตรฐาน แต่รอการตัดบัญชี (เนื่องจากขาดความสนใจ) ดังนั้นจึงมีความเข้าใจผิดเล็กน้อยที่ระบุว่า " มีวิธีมาตรฐาน " โดยระบุ
ผู้ประกอบ

@weaver: โอ้ฉัน! ฉันเรียนรู้สิ่งใหม่ ฉันไม่รู้ว่าเป็นสิ่งที่ฉันต้องการตรวจสอบ
Oddthinking

4
แก้ไขเพื่อให้ทราบว่าไม่ใช่มาตรฐาน ตอนนี้ฉันรู้สึกเขินอายเพราะฉันได้เพิ่มคำขอคุณลักษณะในโครงการที่ขอให้พวกเขาทำตาม "มาตรฐาน" นี้
Oddthinking

1
บางทีคุณควรใช้เวลามากกว่างานมาตรฐานใน PEP ว่าตั้งแต่คุณดูเหมือน :) สนใจ
ทอผ้า

สิ่งนี้จะใช้ได้กับการกำหนดเวอร์ชันโมดูลแต่ละโมดูล แต่ฉันไม่แน่ใจว่าจะใช้กับการกำหนดเวอร์ชันโครงการเต็มรูปแบบ
Stevoisiak

21

แม้ว่านี่อาจจะสายเกินไป แต่ก็มีทางเลือกอื่นที่ง่ายกว่าสำหรับคำตอบก่อนหน้านี้:

__version_info__ = ('1', '2', '3')
__version__ = '.'.join(__version_info__)

(และมันจะค่อนข้างง่ายในการแปลงส่วนที่เพิ่มขึ้นอัตโนมัติของหมายเลขรุ่นเป็นสตริงโดยใช้ str() )

แน่นอนจากสิ่งที่ฉันเคยเห็นผู้คนมักจะใช้บางอย่างเช่นเวอร์ชันที่กล่าวถึงก่อนหน้านี้เมื่อใช้__version_info__งานและเก็บไว้เป็น tuple of ints อย่างไรก็ตามฉันไม่เห็นจุดในการทำเช่นนั้นเพราะฉันสงสัยว่ามีสถานการณ์ที่คุณจะดำเนินการทางคณิตศาสตร์เช่นการบวกและการลบส่วนของหมายเลขรุ่นเพื่อวัตถุประสงค์ใด ๆ นอกเหนือจากความอยากรู้อยากเห็นหรือการเพิ่มอัตโนมัติint()และstr()สามารถใช้งานได้ง่ายพอสมควร) (ในทางกลับกันมีความเป็นไปได้ของรหัสของคนอื่นที่คาดหวังว่าสิ่งอันดับตัวเลขมากกว่า tuple สตริงและทำให้ล้มเหลว)

แน่นอนว่านี่เป็นมุมมองของฉันเองและฉันก็ยินดีที่จะให้ความเห็นของผู้อื่นเกี่ยวกับการใช้ tuple เชิงตัวเลข


ขณะที่ shezi เตือนฉันว่าการเปรียบเทียบ (คำศัพท์) ของสตริงตัวเลขไม่จำเป็นต้องมีผลลัพธ์เช่นเดียวกับการเปรียบเทียบตัวเลขโดยตรง เลขศูนย์นำหน้าจะต้องมีการจัดเตรียมไว้สำหรับสิ่งนั้น ดังนั้นในที่สุดการจัดเก็บ__version_info__(หรือสิ่งที่มันจะเรียกว่า) เป็น tuple ของค่าจำนวนเต็มจะช่วยให้การเปรียบเทียบรุ่นที่มีประสิทธิภาพมากขึ้น


12
ดี (+1) แต่คุณจะไม่ชอบตัวเลขแทนที่จะเป็นสตริงใช่ไหม เช่น__version_info__ = (1,2,3)
orip

3
การเปรียบเทียบสตริงอาจเป็นอันตรายเมื่อหมายเลขเวอร์ชันเกิน 9 เนื่องจากตัวอย่างเช่น '10' <'2'
D Coetzee

13
ฉันทำเช่นนี้เช่นกัน แต่เล็กน้อยเอ็นดูเพื่อ ints อยู่ .. __version_info__ = (0, 1, 0) __version__ = '.'.join(map(str, __version_info__))
rh0dium

2
ปัญหาเกี่ยวกับการ__version__ = '.'.join(__version_info__)เป็นสิ่งที่__version_info__ = ('1', '2', 'beta')จะกลายเป็น1.2.betaไม่ได้1.2betaหรือ1.2 beta
Nagisa

4
ฉันคิดว่าปัญหาของวิธีนี้คือการวางบรรทัดของโค้ดเพื่อประกาศ __version__ หากอยู่ใน setup.py โปรแกรมของคุณจะไม่สามารถนำเข้าจากภายในแพ็คเกจได้ บางทีนี่อาจไม่ใช่ปัญหาสำหรับคุณในกรณีนี้ก็โอเค หากพวกเขาเข้าไปในโปรแกรมของคุณแล้ว setup.py ของคุณสามารถนำเข้าได้ แต่ไม่ควรเนื่องจาก setup.py จะทำงานระหว่างการติดตั้งเมื่อยังไม่ได้ติดตั้งการพึ่งพาของโปรแกรม (setup.py ใช้เพื่อกำหนดว่าการพึ่งพานั้นคืออะไร .) ดังนั้นคำตอบของ Zooko: แยกค่าด้วยตนเองออกจากไฟล์แหล่งผลิตภัณฑ์โดยไม่ต้องนำเข้าแพ็คเกจผลิตภัณฑ์
Jonathan Hartley

11

โซลูชันเหล่านี้จำนวนมากไม่สนใจgitแท็กเวอร์ชันซึ่งยังหมายความว่าคุณต้องติดตามเวอร์ชันในหลาย ๆ ที่ (ไม่ดี) ฉันเข้าหาสิ่งนี้โดยมีเป้าหมายต่อไปนี้:

  • สืบทอดการอ้างอิงแบบหลามทั้งหมดจากแท็กในgitrepo
  • อัตโนมัติgit tag/ pushและsetup.py uploadขั้นตอนด้วยคำสั่งเดียวที่ไม่มีอินพุต

มันทำงานอย่างไร:

  1. จากmake releaseคำสั่งเวอร์ชันที่ติดแท็กล่าสุดใน git repo จะพบและเพิ่มขึ้น originแท็กจะถูกผลักกลับไป

  2. Makefileร้านค้ารุ่นในsrc/_version.pyที่มันจะถูกอ่านโดยsetup.pyและยังรวมถึงในข่าวชิ้นนี้ อย่าเช็คอินที่_version.pyแหล่งควบคุม!

  3. setup.pypackage.__version__คำสั่งอ่านสตริงรุ่นใหม่จาก

รายละเอียด:

Makefile

# remove optional 'v' and trailing hash "v1.0-N-HASH" -> "v1.0-N"
git_describe_ver = $(shell git describe --tags | sed -E -e 's/^v//' -e 's/(.*)-.*/\1/')
git_tag_ver      = $(shell git describe --abbrev=0)
next_patch_ver = $(shell python versionbump.py --patch $(call git_tag_ver))
next_minor_ver = $(shell python versionbump.py --minor $(call git_tag_ver))
next_major_ver = $(shell python versionbump.py --major $(call git_tag_ver))

.PHONY: ${MODULE}/_version.py
${MODULE}/_version.py:
    echo '__version__ = "$(call git_describe_ver)"' > $@

.PHONY: release
release: test lint mypy
    git tag -a $(call next_patch_ver)
    $(MAKE) ${MODULE}/_version.py
    python setup.py check sdist upload # (legacy "upload" method)
    # twine upload dist/*  (preferred method)
    git push origin master --tags

releaseเป้าหมายเสมอเพิ่มขึ้น 3 รุ่นหลัก แต่คุณสามารถใช้next_minor_verหรือnext_major_verเพื่อเพิ่มตัวเลขอื่น ๆ คำสั่งขึ้นอยู่กับversionbump.pyสคริปต์ที่ตรวจสอบลงในรากของ repo

versionbump.py

"""An auto-increment tool for version strings."""

import sys
import unittest

import click
from click.testing import CliRunner  # type: ignore

__version__ = '0.1'

MIN_DIGITS = 2
MAX_DIGITS = 3


@click.command()
@click.argument('version')
@click.option('--major', 'bump_idx', flag_value=0, help='Increment major number.')
@click.option('--minor', 'bump_idx', flag_value=1, help='Increment minor number.')
@click.option('--patch', 'bump_idx', flag_value=2, default=True, help='Increment patch number.')
def cli(version: str, bump_idx: int) -> None:
    """Bumps a MAJOR.MINOR.PATCH version string at the specified index location or 'patch' digit. An
    optional 'v' prefix is allowed and will be included in the output if found."""
    prefix = version[0] if version[0].isalpha() else ''
    digits = version.lower().lstrip('v').split('.')

    if len(digits) > MAX_DIGITS:
        click.secho('ERROR: Too many digits', fg='red', err=True)
        sys.exit(1)

    digits = (digits + ['0'] * MAX_DIGITS)[:MAX_DIGITS]  # Extend total digits to max.
    digits[bump_idx] = str(int(digits[bump_idx]) + 1)  # Increment the desired digit.

    # Zero rightmost digits after bump position.
    for i in range(bump_idx + 1, MAX_DIGITS):
        digits[i] = '0'
    digits = digits[:max(MIN_DIGITS, bump_idx + 1)]  # Trim rightmost digits.
    click.echo(prefix + '.'.join(digits), nl=False)


if __name__ == '__main__':
    cli()  # pylint: disable=no-value-for-parameter

นี่เป็นการยกระดับวิธีการประมวลผลและเพิ่มหมายเลขรุ่นจาก gitนี้ไม่ยกของหนักวิธีการกระบวนการและการเพิ่มหมายเลขรุ่นจาก

__init__.py

ไฟล์ถูกนำเข้ามาในmy_module/_version.py my_module/__init__.pyใส่การตั้งค่าการติดตั้งแบบคงที่ใด ๆ ที่คุณต้องการกระจายกับโมดูลของคุณ

from ._version import __version__
__author__ = ''
__email__ = ''

setup.py

ขั้นตอนสุดท้ายคือการอ่านข้อมูลรุ่นจากmy_moduleโมดูล

from setuptools import setup, find_packages

pkg_vars  = {}

with open("{MODULE}/_version.py") as fp:
    exec(fp.read(), pkg_vars)

setup(
    version=pkg_vars['__version__'],
    ...
    ...
)

แน่นอนว่าเพื่อให้การทำงานทั้งหมดนี้คุณต้องมีแท็กเวอร์ชันอย่างน้อยหนึ่งแท็กใน repo ของคุณเพื่อเริ่มต้น

git tag -a v0.0.1

1
แน่นอน - เธรดทั้งหมดนี้ลืมว่า VCS มีความสำคัญมากในการสนทนานี้ เพียงแค่ obs: การเพิ่มรุ่นควรเป็นกระบวนการแบบแมนนวลดังนั้นวิธีที่ต้องการคือ 1. สร้างและกดแท็กด้วยตนเอง 2. ให้เครื่องมือ VCS ค้นพบแท็กนั้นและเก็บไว้ในที่ที่จำเป็น (ว้าว - อินเทอร์เฟซการแก้ไขนี้ - ฉันต้องแก้ไขสิ่งนี้โหลเพื่อจัดการกับ newlines และมันยังไม่ทำงาน! @ # $% ^ & *)
axd

ไม่จำเป็นต้องใช้versionbump.pyเมื่อเรามีแพ็คเกจbumpversion ที่ยอดเยี่ยมสำหรับ python
Oran

@Oran ฉันดู versionbump เอกสารไม่ชัดเจนมากและไม่สามารถจัดการกับการติดแท็กได้เป็นอย่างดี ในการทดสอบของฉันดูเหมือนว่าจะเข้าสู่สถานะที่ทำให้เกิดความผิดพลาด: subprocess.CalledProcessError: คำสั่ง '[' git ',' commit ',' -F ',' / var / โฟลเดอร์ / rl / tjyk4hns7kndnx035p26wg692g_7t8 / T / tmppishishbo ' 'คืนสถานะการออกที่ไม่เป็นศูนย์ 1
cmcginty

1
ทำไมไม่ควร_version.pyติดตามด้วยการควบคุมเวอร์ชัน?
Stevoisiak

1
@StevenVascellaro ขั้นตอนนี้จะทำให้กระบวนการปล่อยซับซ้อน ตอนนี้คุณต้องตรวจสอบให้แน่ใจว่าคุณมีแท็กและการคอมมิชชันตรงกับค่าใน _version.py การใช้แท็กเวอร์ชันเดียวนั้นสะอาดกว่า IMO และหมายความว่าคุณสามารถสร้างการเปิดตัวได้โดยตรงจาก Github UI
cmcginty

10

ฉันใช้ไฟล์ JSON ในแพ็คเกจ dir ตรงกับข้อกำหนดของ Zooko

ภายในpkg_dir/pkg_info.json:

{"version": "0.1.0"}

ภายในsetup.py:

from distutils.core import setup
import json

with open('pkg_dir/pkg_info.json') as fp:
    _info = json.load(fp)

setup(
    version=_info['version'],
    ...
    )

ภายในpkg_dir/__init__.py:

import json
from os.path import dirname

with open(dirname(__file__) + '/pkg_info.json') as fp:
    _info = json.load(fp)

__version__ = _info['version']

ฉันยังใส่ข้อมูลอื่น ๆpkg_info.jsonเช่นผู้เขียน ฉันชอบใช้ JSON เพราะฉันสามารถจัดการข้อมูลเมตาได้โดยอัตโนมัติ


คุณสามารถอธิบายวิธีการใช้ json ในการจัดการ metadata อัตโนมัติได้อย่างไร? ขอบคุณ!
ryanjdillon

6

นอกจากนี้ยังมีข้อสังเกตว่ามันคุ้มค่าเช่นเดียวกับ__version__การเป็นกึ่งมาตรฐาน ใน python ดังนั้น__version_info__ซึ่งเป็น tuple ในกรณีง่าย ๆ คุณสามารถทำสิ่งที่ชอบ:

__version__ = '1.2.3'
__version_info__ = tuple([ int(num) for num in __version__.split('.')])

... และคุณสามารถรับ__version__สตริงจากไฟล์หรืออะไรก็ได้


1
คุณมีการอ้างอิง / ลิงค์เกี่ยวกับที่มาของการใช้งานนี้__version_info__หรือไม่?
Craig McQueen

3
มันเป็นแผนที่เดียวกันกับ sys.version กับ sys.version_info ดังนั้น: docs.python.org/library/sys.html#sys.version_info
James Antill

7
การทำแผนที่ในทิศทางอื่นจะง่ายกว่า ( __version_info__ = (1, 2, 3)และ__version__ = '.'.join(map(str, __version_info__)))
Eric O Lebigot

2
@EOL - __version__ = '.'.join(str(i) for i in __version_info__)- อีกต่อไปเล็กน้อย แต่ pythonic เพิ่มเติม
ArtOfWarfare

2
ฉันไม่แน่ใจว่าสิ่งที่คุณเสนอนั้นชัดเจนกว่า pythonic เพราะมันมีตัวแปรดัมมี่ที่ไม่ต้องการจริงๆและความหมายของมันยากที่จะแสดงออกเล็กน้อย ( iไม่มีความหมายversion_numมีความยาวและคลุมเครือเล็กน้อย…) ฉันยังคงมีอยู่map()ใน Python เป็นนัยสำคัญที่ควรใช้ที่นี่เนื่องจากสิ่งที่เราต้องทำที่นี่คือกรณีการใช้งานทั่วไปของmap()(ใช้กับฟังก์ชันที่มีอยู่) - ฉันไม่เห็นการใช้ที่สมเหตุสมผลอื่น ๆ อีกมากมาย
Eric O Lebigot

5

ดูเหมือนจะไม่มีวิธีมาตรฐานในการฝังสตริงเวอร์ชันในแพ็คเกจหลาม แพ็คเกจส่วนใหญ่ที่ฉันเคยเห็นใช้โซลูชันของคุณบางอย่างเช่น eitner

  1. ฝังรุ่นในsetup.pyและsetup.pyสร้างโมดูล (เช่นversion.py) ที่มีเฉพาะข้อมูลรุ่นซึ่งนำเข้าจากแพ็คเกจของคุณหรือ

  2. ย้อนกลับ: ใส่ข้อมูลรุ่นในแพ็คเกจของคุณเองและนำเข้าสิ่งนั้นเพื่อตั้งค่ารุ่น setup.py


ฉันชอบคำแนะนำของคุณ แต่จะสร้างโมดูลนี้จาก setup.py ได้อย่างไร
โซริน

1
ฉันชอบแนวคิดของตัวเลือก (1) ดูเหมือนจะง่ายกว่าคำตอบของ Zooko ในการแยกวิเคราะห์หมายเลขรุ่นจากไฟล์ แต่คุณไม่สามารถมั่นใจได้ว่า version.py จะถูกสร้างขึ้นเมื่อนักพัฒนาเพียงแค่โคลนโคลน repo ของคุณ หากคุณไม่ตรวจสอบใน version.py ซึ่งจะเปิดรอยย่นเล็ก ๆ ที่คุณอาจเปลี่ยนหมายเลขรุ่นใน setup.py, กระทำ, ปล่อยและจากนั้นจะต้อง (เฉือนลืม) กระทำการเปลี่ยนแปลงเป็น version.py
Jonathan Hartley

สมมุติว่าคุณสามารถสร้างโมดูลโดยใช้บางอย่างเช่น "" "พร้อม open (" mypackage / version.py "," w ") เป็น fp: fp.write (" __ version__ == '% s' \ n "% (__version__,) ) "" "
Jonathan Hartley

1
ฉันคิดว่าตัวเลือกที่ 2 มีความไวต่อความล้มเหลวระหว่างการติดตั้งดังที่ระบุไว้ในความคิดเห็นต่อคำตอบของ JAB
Jonathan Hartley

แล้วเรื่องอะไรล่ะ คุณใส่ __version__ = '0.0.1' "(ซึ่งเป็นรุ่นของสตริง) ใน __init__.py" ของแพ็คเกจหลักของซอฟต์แวร์ของคุณ จากนั้นไปที่จุดที่ 2: ในการตั้งค่าที่คุณทำจากแพ็คเกจ __ init__ นำเข้า __version__ เป็น v จากนั้นคุณตั้งค่าตัวแปร v เป็นเวอร์ชันของ setup.py ของคุณ จากนั้นนำเข้า mypack เป็นของฉันให้พิมพ์. __ version__ ของฉันเพื่อพิมพ์เวอร์ชัน เวอร์ชันจะถูกเก็บไว้ในที่เดียวซึ่งสามารถเข้าถึงได้จากรหัสทั้งหมดในไฟล์ที่ไม่นำเข้าสิ่งอื่นที่เกี่ยวข้องกับซอฟต์แวร์
SeF

5

ลูกศรจัดการกับมันในวิธีที่น่าสนใจ

ตอนนี้ (ตั้งแต่2e5031b )

ในarrow/__init__.py:

__version__ = 'x.y.z'

ในsetup.py:

from arrow import __version__

setup(
    name='arrow',
    version=__version__,
    # [...]
)

ก่อน

ในarrow/__init__.py:

__version__ = 'x.y.z'
VERSION = __version__

ในsetup.py:

def grep(attrname):
    pattern = r"{0}\W*=\W*'([^']+)'".format(attrname)
    strval, = re.findall(pattern, file_text)
    return strval

file_text = read(fpath('arrow/__init__.py'))

setup(
    name='arrow',
    version=grep('__version__'),
    # [...]
)

คือfile_textอะไร
ely

2
โซลูชันที่อัปเดตแล้วเป็นอันตรายจริง ๆ เมื่อ setup.py กำลังทำงานจะไม่จำเป็นต้องดูเวอร์ชันของแพ็กเกจจากพา ธ ไฟล์โลคัล มันอาจเปลี่ยนกลับเป็นเวอร์ชันที่ติดตั้งไว้ก่อนหน้าเช่นจากการทำงานpip install -e .ในสาขาการพัฒนาหรือบางอย่างเมื่อทำการทดสอบ setup.py ไม่ควรพึ่งพาการนำเข้าแพ็คเกจที่อยู่ในกระบวนการติดตั้งเพื่อกำหนดพารามิเตอร์สำหรับการปรับใช้ Yikes
ely

ใช่ฉันไม่รู้ว่าทำไมลูกศรตัดสินใจถอยกลับไปใช้โซลูชันนี้ นอกจากนี้ข้อความการส่งข้อความยังระบุว่า "อัปเดต setup.py พร้อมด้วยมาตรฐาน Python ที่ทันสมัย " ... 🤷
Anto

4

ฉันเห็นสไตล์อื่นด้วย:

>>> django.VERSION
(1, 1, 0, 'final', 0)

1
ใช่ฉันเห็นด้วย BTW ทุกคำตอบใช้รูปแบบอื่นดังนั้นตอนนี้ฉันไม่รู้ว่ารูปแบบคือ "มาตรฐาน" กำลังมองหา
PEPs ที่

อีกวิธีหนึ่งที่เห็น; ลูกค้า Python ของ Mongo ใช้รุ่นธรรมดาโดยไม่มีขีดล่าง ดังนั้นงานนี้; $ python >>> import pymongo >>> pymongo.version '2.7'
AnneTheAgile

ใช้งานไม่ได้หมายความว่าคุณไม่ได้มีการดำเนินการ.VERSION __version__
คิวเมนตัส

สิ่งนี้จำเป็นต้องใช้djangoในโครงการหรือไม่?
Stevoisiak

3

การใช้setuptoolsและpbr

ไม่มีวิธีมาตรฐานในการจัดการเวอร์ชัน แต่วิธีมาตรฐานในการจัดการแพ็คเกจของคุณคือ setuptoolsแต่วิธีมาตรฐานในการจัดการแพคเกจของคุณจะ

ทางออกที่ดีที่สุดที่ฉันพบโดยรวมสำหรับการจัดการเวอร์ชันคือการใช้setuptoolsกับpbrส่วนขยาย นี่เป็นวิธีมาตรฐานในการจัดการเวอร์ชันของฉัน

การตั้งค่าโครงการของคุณสำหรับบรรจุภัณฑ์เต็มอาจเกินความจำเป็นสำหรับโครงการง่าย ๆ แต่ถ้าคุณต้องการจัดการเวอร์ชันคุณอาจอยู่ในระดับที่เหมาะสมในการตั้งค่าทุกอย่าง การทำเช่นนี้ยังช่วยให้แพคเกจของคุณ releasable ที่PyPiสามารถใช้งานได้เพื่อให้ทุกคนสามารถดาวน์โหลดและใช้กับ Pip ได้

PBR ย้ายข้อมูลเมตาส่วนใหญ่ออกจากsetup.pyเครื่องมือและเป็นsetup.cfgไฟล์ที่ใช้เป็นแหล่งข้อมูลเมตาดาต้าส่วนใหญ่ซึ่งอาจรวมถึงรุ่น สิ่งนี้ทำให้เมตะดาต้าสามารถจัดทำเป็นแพคเกจได้โดยใช้บางอย่างpyinstallerถ้าจำเป็น (ถ้าเป็นเช่นนั้นคุณอาจต้องใช้ข้อมูลนี้ ) และแยกเมทาดาทาออกจากสคริปต์การจัดการ / เซ็ตอัพแพ็คเกจอื่น ๆ คุณสามารถอัปเดตสตริงเวอร์ชันโดยตรงsetup.cfgด้วยตนเองและมันจะถูกดึงเข้าไปใน*.egg-infoโฟลเดอร์เมื่อสร้างแพ็คเกจของคุณ สคริปต์ของคุณสามารถเข้าถึงเวอร์ชันจากข้อมูลเมตาโดยใช้วิธีการต่าง ๆ (กระบวนการเหล่านี้มีการอธิบายไว้ในส่วนด้านล่าง)

เมื่อใช้ Git สำหรับ VCS / SCM การตั้งค่านี้จะดียิ่งขึ้นเนื่องจากมันจะดึงข้อมูลเมตาจำนวนมากจาก Git เพื่อให้ repo ของคุณสามารถเป็นแหล่งข้อมูลหลักของความจริงสำหรับข้อมูลเมตาบางส่วนรวมถึงรุ่นผู้เขียนรายการเปลี่ยนแปลง เป็นต้นสำหรับรุ่นโดยเฉพาะมันจะสร้างสตริงรุ่นสำหรับการกระทำปัจจุบันตามแท็ก git ใน repo

เนื่องจาก PBR จะดึงเวอร์ชันผู้สร้างการเปลี่ยนแปลงและข้อมูลอื่น ๆ โดยตรงจาก repo git ของคุณดังนั้นเมทาดาทาบางส่วนsetup.cfgสามารถถูกปล่อยออกมาและสร้างอัตโนมัติเมื่อใดก็ตามที่มีการสร้างการแจกจ่ายสำหรับแพ็คเกจของคุณ (โดยใช้setup.py )

รุ่นปัจจุบันเรียลไทม์

setuptoolsจะดึงข้อมูลล่าสุดแบบเรียลไทม์โดยใช้setup.py:

python setup.py --version

สิ่งนี้จะดึงเวอร์ชันล่าสุดทั้งจากsetup.cfgไฟล์หรือจาก git repo โดยยึดตามการคอมมิทล่าสุดที่สร้างขึ้นและแท็กที่มีอยู่ใน repo คำสั่งนี้ไม่ได้อัปเดตเวอร์ชันในการแจกจ่าย

กำลังอัปเดตเวอร์ชัน

เมื่อคุณสร้างการแจกจ่ายด้วยsetup.py( py setup.py sdistตัวอย่างเช่น) จากนั้นข้อมูลปัจจุบันทั้งหมดจะถูกแยกและจัดเก็บไว้ในการกระจาย สิ่งนี้จะรันsetup.py --versionคำสั่งจากนั้นเก็บข้อมูลรุ่นนั้นไว้ในpackage.egg-infoโฟลเดอร์ในชุดของไฟล์ที่เก็บข้อมูลเมตาของการแจกจ่าย

หมายเหตุเกี่ยวกับกระบวนการอัปเดตข้อมูลเมตารุ่น:

หากคุณไม่ได้ใช้ pbr เพื่อดึงข้อมูลเวอร์ชันจาก git เพียงอัปเดต setup.cfg ของคุณโดยตรงด้วยข้อมูลเวอร์ชันใหม่ (ง่ายพอ แต่ให้แน่ใจว่านี่เป็นส่วนมาตรฐานของกระบวนการวางจำหน่ายของคุณ)

หากคุณใช้ git และคุณไม่จำเป็นต้องสร้างแหล่งที่มาหรือการแจกแจงแบบไบนารี (การใช้python setup.py sdistหรือpython setup.py bdist_xxxคำสั่งอย่างใดอย่างหนึ่ง) วิธีที่ง่ายที่สุดในการอัปเดตข้อมูล git repo ลงใน<mypackage>.egg-infoโฟลเดอร์ข้อมูลเมตาของคุณคือการเรียกใช้python setup.py installคำสั่ง สิ่งนี้จะเรียกใช้ฟังก์ชัน PBR ทั้งหมดที่เกี่ยวข้องกับการดึงข้อมูลเมตาจาก git repo และอัปเดต.egg-infoโฟลเดอร์ในเครื่องของคุณติดตั้งโปรแกรมปฏิบัติการสคริปต์สำหรับจุดเข้าใช้งานใด ๆ ที่คุณกำหนดไว้และฟังก์ชั่นอื่น ๆ

โปรดทราบว่า.egg-infoโดยทั่วไปโฟลเดอร์จะถูกยกเว้นไม่ให้ถูกเก็บไว้ใน git repo ใน.gitignoreไฟล์Python มาตรฐาน(เช่นจากGitignore.IO ) เนื่องจากสามารถสร้างได้จากแหล่งที่มาของคุณ หากไม่ได้รับการยกเว้นตรวจสอบให้แน่ใจว่าคุณมี "กระบวนการเผยแพร่" มาตรฐานเพื่อรับข้อมูลเมตาที่อัปเดตในเครื่องก่อนที่จะเผยแพร่และแพ็คเกจใด ๆ ที่คุณอัปโหลดไปยัง PyPi.org หรือเผยแพร่อย่างอื่นจะต้องมีข้อมูลนี้ หากคุณต้องการให้ Git repo มีข้อมูลนี้คุณสามารถยกเว้นไฟล์บางไฟล์จากการถูกละเว้น (เช่นเพิ่ม!*.egg-info/PKG_INFOไป.gitignore)

การเข้าถึงเวอร์ชันจากสคริปต์

คุณสามารถเข้าถึงข้อมูลเมตาได้จากบิลด์ปัจจุบันภายในสคริปต์ Python ในแพ็คเกจเอง ตัวอย่างเช่นสำหรับรุ่นมีหลายวิธีในการทำเช่นนี้ฉันได้พบ:

## This one is a new built-in as of Python 3.8.0 should become the standard
from importlib-metadata import version

v0 = version("mypackage")
print('v0 {}'.format(v0))

## I don't like this one because the version method is hidden
import pkg_resources  # part of setuptools

v1 = pkg_resources.require("mypackage")[0].version
print('v1 {}'.format(v1))

# Probably best for pre v3.8.0 - the output without .version is just a longer string with
# both the package name, a space, and the version string
import pkg_resources  # part of setuptools

v2 = pkg_resources.get_distribution('mypackage').version
print('v2 {}'.format(v2))

## This one seems to be slower, and with pyinstaller makes the exe a lot bigger
from pbr.version import VersionInfo

v3 = VersionInfo('mypackage').release_string()
print('v3 {}'.format(v3))

คุณสามารถใส่หนึ่งในสิ่งเหล่านี้ลงใน__init__.pyแพคเกจของคุณโดยตรงเพื่อดึงข้อมูลเวอร์ชั่นดังต่อไปนี้คล้ายกับคำตอบอื่น ๆ :

__all__ = (
    '__version__',
    'my_package_name'
)

import pkg_resources  # part of setuptools

__version__ = pkg_resources.get_distribution("mypackage").version

จัดรูปแบบใหม่ต่อการลงคะแนนเพื่อตอบคำถามทันที
LightCC

1

หลังจากหลายชั่วโมงของการพยายามหาวิธีแก้ปัญหาที่เชื่อถือได้ง่ายที่สุดนี่คือส่วนต่างๆ:

สร้างไฟล์ version.py ภายในโฟลเดอร์ของแพ็คเกจ "/ mypackage":

# Store the version here so:
# 1) we don't load dependencies by storing it in __init__.py
# 2) we can import it in setup.py for the same reason
# 3) we can import it into your module module
__version__ = '1.2.7'

ใน setup.py:

exec(open('mypackage/version.py').read())
setup(
    name='mypackage',
    version=__version__,

ในโฟลเดอร์หลักinit .py:

from .version import __version__

exec()ฟังก์ชั่นทำงานนอกสคริปต์ของการนำเข้าใด ๆ ตั้งแต่ setup.py จะดำเนินการก่อนที่จะโมดูลสามารถนำเข้า คุณยังต้องจัดการหมายเลขเวอร์ชันในไฟล์เดียวในที่เดียว แต่น่าเสียดายที่มันไม่ได้อยู่ใน setup.py (นั่นคือข้อเสีย แต่ไม่มีข้อบกพร่องในการนำเข้าคือคว่ำ)


1

จำนวนมากของการทำงานที่มีต่อเวอร์ชันสม่ำเสมอและในการสนับสนุนการประชุมเสร็จเรียบร้อยแล้วตั้งแต่คำถามนี้ถูกถามครั้งแรก ตัวเลือกอร่อยตอนนี้รายละเอียดในคู่มือการใช้บรรจุภัณฑ์หลาม ที่น่าสังเกตก็คือรูปแบบหมายเลขรุ่นนั้นค่อนข้างเข้มงวดใน Python ต่อ PEP 440ดังนั้นการรักษาสิ่งต่าง ๆ จึงมีความสำคัญหากแพ็คเกจของคุณจะถูกปล่อยออกสู่ร้านชีสร้านชีส

นี่คือรายละเอียดตัวเลือกการกำหนดเวอร์ชันที่สั้นลง:

  1. อ่านไฟล์ในsetup.py( setuptools ) และรับรุ่น
  2. ใช้เป็นเครื่องมือสร้างภายนอก (อัปเดตทั้งสอง__init__.pyเช่นเดียวกับการควบคุมแหล่งที่มา) เช่นbump2version , การเปลี่ยนแปลงหรือzest.releaser zest.releaser
  3. ตั้งค่าเป็น __version__ตัวแปรโกลบอลในโมดูลเฉพาะ
  4. วางค่าในไฟล์ข้อความ VERSION แบบง่าย ๆ เพื่อให้ setup.py และโค้ดอ่าน
  5. ตั้งค่าผ่านรีsetup.pyลีสและใช้importlib.metadataเพื่อรับมันที่รันไทม์ (คำเตือนมีรุ่นก่อน 3.8 และรุ่นหลัง 3.8)
  6. ตั้งค่าเป็น__version__ในsample/__init__.pyและนำเข้าในกลุ่มตัวอย่างsetup.pyและนำเข้าในกลุ่มตัวอย่าง
  7. ใช้setuptools_scmเพื่อแยกการควบคุมเวอร์ชันจากแหล่งที่มาเพื่อให้เป็นข้อมูลอ้างอิงแบบบัญญัติไม่ใช่รหัส

โปรดทราบว่า (7) อาจเป็นวิธีการที่ทันสมัยที่สุด (build metadata ไม่ขึ้นกับโค้ดที่เผยแพร่โดยระบบอัตโนมัติ) นอกจากนี้โปรดทราบว่าหากใช้การตั้งค่าสำหรับการเปิดตัวแพคเกจที่ง่ายpython3 setup.py --versionจะรายงานรุ่นโดยตรง


-1

สำหรับสิ่งที่คุ้มค่าถ้าคุณกำลังใช้ distutils NumPy, numpy.distutils.misc_util.Configurationมีmake_svn_version_py()วิธีการที่ฝังอยู่ภายในจำนวนการแก้ไขในตัวแปรpackage.__svn_version__version


คุณสามารถให้รายละเอียดเพิ่มเติมหรือตัวอย่างของวิธีการทำงานได้หรือไม่
Stevoisiak

อืมมม ในปี 2020 สิ่งนี้มีไว้สำหรับFORTRANหรือไม่ แพ็คเกจ "numpy.distutils เป็นส่วนหนึ่งของ NumPy ที่ขยาย Python distutils มาตรฐานเพื่อจัดการกับแหล่ง Fortran"
ingyhere

-1
  1. ใช้version.pyไฟล์กับ__version__ = <VERSION>param ในไฟล์เท่านั้น ในsetup.pyไฟล์ที่นำเข้า__version__พารามิเตอร์และใส่ค่าลงในsetup.pyไฟล์ดังนี้: version=__version__
  2. อีกวิธีคือใช้setup.pyไฟล์ด้วยversion=<CURRENT_VERSION>- CURRENT_VERSION นั้นฮาร์ดโค้ด

เนื่องจากเราไม่ต้องการเปลี่ยนเวอร์ชันในไฟล์ด้วยตนเองทุกครั้งที่เราสร้างแท็กใหม่ (พร้อมที่จะปล่อยเวอร์ชันแพ็คเกจใหม่) เราสามารถใช้สิ่งต่อไปนี้ ..

ฉันขอแนะนำแพ็คเกจbumpversion ฉันใช้มันเป็นเวลาหลายปีในการชนรุ่น

เริ่มต้นด้วยการเพิ่มversion=<VERSION>ลงในsetup.pyไฟล์ของคุณหากคุณยังไม่มี

คุณควรใช้สคริปต์สั้น ๆ แบบนี้ทุกครั้งที่คุณเจอเวอร์ชั่น:

bumpversion (patch|minor|major) - choose only one option
git push
git push --tags

จากนั้นเพิ่มหนึ่งไฟล์ต่อ repo ที่เรียกว่า.bumpversion.cfg::

[bumpversion]
current_version = <CURRENT_TAG>
commit = True
tag = True
tag_name = {new_version}
[bumpversion:file:<RELATIVE_PATH_TO_SETUP_FILE>]

บันทึก:

  • คุณสามารถใช้__version__พารามิเตอร์ภายใต้version.pyไฟล์เหมือนที่แนะนำในโพสต์อื่น ๆ และอัปเดตไฟล์ bumpversion ดังนี้: [bumpversion:file:<RELATIVE_PATH_TO_VERSION_FILE>]
  • คุณต้อง git commitหรือgit resetทุกอย่างใน repo ของคุณมิฉะนั้นคุณจะได้รับข้อผิดพลาด repo ที่สกปรก
  • ตรวจสอบให้แน่ใจว่าสภาพแวดล้อมเสมือนจริงของคุณมีแพ็คเกจของ bumpversion โดยที่ไม่มีมันจะใช้งานไม่ได้

@cmcginty ขออภัยในความล่าช้าโปรดตรวจสอบคำตอบของฉัน ^^^ - โปรดทราบว่าคุณต้องคอมไพล์คอมไพล์หรือตั้งค่าทุกอย่างใน repo ของคุณและตรวจสอบให้แน่ใจว่าสภาพแวดล้อมเสมือนของคุณมีแพ็คเกจbumpversionโดยที่มันจะไม่ทำงาน ใช้รุ่นล่าสุด
Oran

ฉันค่อนข้างชัดเจนเกี่ยวกับวิธีการแก้ปัญหาที่ถูกแนะนำที่นี่ คุณแนะนำตนเองติดตามรุ่นด้วยversion.pyหรือติดตามมันด้วยbumpversion?
Stevoisiak

@StevenVascellaro ฉันแนะนำให้ใช้ bumpversion อย่าใช้การกำหนดเวอร์ชันด้วยตนเอง สิ่งที่ฉันพยายามอธิบายคือคุณสามารถกำหนดให้ bumpversion อัปเดตทั้งเวอร์ชันในไฟล์ setup.py หรือดีกว่ายังใช้เพื่ออัปเดตไฟล์ version.py เป็นเรื่องธรรมดาที่จะอัปเดตไฟล์ version.py และนำ__version__ค่าพารามิเตอร์เข้าไปในไฟล์ setup.py โซลูชันของฉันใช้ในการผลิตและเป็นวิธีปฏิบัติทั่วไป หมายเหตุ: เพื่อให้ชัดเจนโดยใช้ bumpversion เป็นส่วนหนึ่งของสคริปต์เป็นทางออกที่ดีที่สุดวางไว้ใน CI ของคุณและมันจะเป็นการทำงานอัตโนมัติ
โอแรน

-3

หากคุณใช้ CVS (หรือ RCS) และต้องการวิธีแก้ปัญหาอย่างรวดเร็วคุณสามารถใช้:

__version__ = "$Revision: 1.1 $"[11:-2]
__version_info__ = tuple([int(s) for s in __version__.split(".")])

(แน่นอนหมายเลขการแก้ไขจะถูกแทนที่ด้วย CVS สำหรับคุณ)

สิ่งนี้จะให้รุ่นที่เหมาะกับการพิมพ์และข้อมูลรุ่นที่คุณสามารถใช้เพื่อตรวจสอบว่าโมดูลที่คุณกำลังนำเข้ามีอย่างน้อยรุ่นที่คาดหวัง:

import my_module
assert my_module.__version_info__ >= (1, 1)

คุณแนะนำให้บันทึกไฟล์ประเภท__version__ใด หนึ่งจะเพิ่มหมายเลขรุ่นด้วยวิธีนี้ได้อย่างไร
Stevoisiak
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.