ใช้งานสคริปต์ Python ด้วย uv และ PEP 723
(cottongeeks.com)- ตัวจัดการแพ็กเกจ uv และ PEP 723 ช่วยให้สามารถรันสคริปต์ Python ได้โดยไม่ต้องกังวลเรื่อง dependency
- ฟีเจอร์ uvx จะสร้าง virtual environment แบบชั่วคราวให้อัตโนมัติ ช่วยแก้ปัญหาความยุ่งยากในการตั้งค่าสภาพแวดล้อม
- หากใส่ เมทาดาทา PEP 723 ไว้ในไฟล์ Python จะช่วยให้การรันสคริปต์และการจัดการแพ็กเกจเป็นไปโดยอัตโนมัติและสะดวกขึ้น
- มี ตัวอย่างสคริปต์ใช้งานจริง ที่สามารถนำไปสร้างและแจกจ่ายโปรแกรมดึงคำบรรยาย YouTube ได้อย่างรวดเร็ว
- ทำให้ตอนนี้ Python ก็สามารถ เขียนไฟล์รันเดี่ยวแบบกระชับ ได้แล้ว และเพิ่มความคล่องตัวในการใช้งานสคริปต์อย่างมาก
ภาพรวม
- เดิมทีการรัน "สคริปต์ใช้ครั้งเดียว (one-off script)" ใน Python มักต้องตั้งค่าสภาพแวดล้อมและติดตั้งแพ็กเกจใหม่ทุกครั้ง แต่เมื่อมี uv และ PEP 723 ปัญหานี้ก็แทบหมดไป
- uv คือ ตัวจัดการแพ็กเกจและโปรเจกต์ Python ความเร็วสูง ที่พัฒนาด้วย Rust และมีฟีเจอร์ใหม่อย่าง uvx ซึ่งช่วยจัดการ virtual environment แบบชั่วคราว การติดตั้งแพ็กเกจอัตโนมัติ และการผูกกับเวอร์ชัน Python ได้อย่างรวดเร็วและง่ายมาก
ข้อดีของ uv และ uvx
- ฟีเจอร์ uvx ทำงานคล้าย npx ใน ecosystem ของ Nodejs โดยจะสร้างสภาพแวดล้อมสำหรับรันแพ็กเกจ Python ที่ระบุไว้ (เช่น ruff) ได้อย่างรวดเร็ว
- ใช้ disposable virtual environment ผ่านระบบแคช จึงรันได้รวดเร็วโดยแทบไม่มี overhead
- การตั้งค่าสภาพแวดล้อมและติดตั้ง dependency ทำได้ด้วยคำสั่งบรรทัดเดียว ทำให้นักพัฒนาไม่ต้องดูแลการตั้งค่าสภาพแวดล้อมแยกต่างหาก
แนะนำ PEP 723 และการใช้งาน
- PEP 723 เป็นมาตรฐานที่กำหนดให้สามารถใส่ เมทาดาทาด้าน dependency และสภาพแวดล้อม ไว้ที่ส่วนบนของสคริปต์ Python ได้
- ตัวอย่างเช่น สามารถระบุ requires-python, dependencies เป็นต้น ไว้ที่ด้านบนของโค้ดได้
- เครื่องมือภายนอกที่รองรับข้อมูลนี้ (เช่น uv) จะใช้ข้อมูลในไฟล์สคริปต์เพื่อติดตั้งแพ็กเกจ ตั้งค่าสภาพแวดล้อม และรันโปรแกรมให้อัตโนมัติ
การผสาน uv กับ PEP 723
- ในตัวอย่างจริง เมื่อนำเมทาดาทานี้ไปเขียนไว้ด้านบนของไฟล์ Python แล้วรันด้วยคำสั่ง
uv runระบบจะติดตั้งแพ็กเกจที่จำเป็นทั้งหมด ตั้งค่าเวอร์ชัน Python ตามที่กำหนด และรันโค้ดทันที - โค้ดตัวอย่างจะเรียกใช้งาน API บนอินเทอร์เน็ต (รายการ PEP) และแสดงผลลัพธ์ โดยไม่ต้องติดตั้งแพ็กเกจเพิ่มเติมหรือตั้งค่าสภาพแวดล้อมเอง สามารถรันได้ด้วยคำสั่งบรรทัดเดียว
ตัวอย่างการใช้งานจริง: สคริปต์คำบรรยาย YouTube
- มีตัวอย่างสคริปต์ Python ที่เพิ่ม shebang(
#!/usr/bin/env -S uv run --script) และเมทาดาทา PEP 723 - รองรับการติดตั้งแพ็กเกจภายนอกอย่าง youtube-transcript-api อัตโนมัติ พร้อมตั้งค่า virtual environment ให้อัตโนมัติ
- ผู้ใช้สามารถส่ง URL หรือ ID ของวิดีโอ YouTube เป็นอาร์กิวเมนต์ให้ไฟล์รัน (
ytt) เพื่อดึงคำบรรยายและรับผลลัพธ์ได้ทันที - หลังให้สิทธิ์รันด้วย
chmodแล้ว ก็สามารถเรียกใช้งานจากเทอร์มินัลได้อย่างง่ายดาย
ประสบการณ์นักพัฒนาที่ดีขึ้นและการขยายขอบเขตการใช้งาน
- ในอดีต แม้แต่การรันสคริปต์ง่าย ๆ ผู้ใช้ก็มักเอนเอียงไปหา Go หรือภาษาแบบไบนารีไฟล์เดี่ยวมากกว่า แต่ตอนนี้ Python ก็ให้ความสะดวกในระดับใกล้เคียงกันได้แล้ว
- การผสาน uv กับ PEP 723 ทำให้การแชร์ การแจกจ่าย และการทำงานอัตโนมัติของสคริปต์ Python ง่ายขึ้นอย่างมาก
- มีตัวอย่างบน GitHub (cottongeeks/ytt-mcp) ที่สามารถนำไปต่อยอดสู่กรณีใช้งานที่ซับซ้อนยิ่งขึ้นได้
2 ความคิดเห็น
uvเร็วมากจริง ๆ เลยชอบมากครับ/ค่ะ ช่วงนี้ก็เลยใช้uvทุกที่ที่เป็นไปได้ความคิดเห็นจาก Hacker News
ช่วงนี้ก็เหมือนผู้เขียน คือหยิบ Python แบบครอสแพลตฟอร์มสำหรับงาน one-off และสคริปต์ส่วนตัวมาใช้บ่อยกว่า Go แต่ก็ยังไม่ค่อยพอใจกับสภาพของระบบตรวจเช็ก type ของ Python ที่ยังสับสนสุด ๆ หวังว่าเครื่องมืออย่าง ty, pyrefly จะช่วยให้ดีขึ้นได้บ้าง
ตอนนี้รู้สึกว่าสคริปต์ Python ใช้งานได้ลื่นเลยโดยไม่ต้องทุกข์กับ virtualenv อีกต่อไป เลยคิดว่าน่าจะดีถ้าฝั่ง shell script ก็มีประสบการณ์แบบนี้บ้าง เรื่อง packaging, การจัดการ dependency และ reproducibility ยังเหมือนอยู่ในยุคหิน ตอนนี้ก็ยังมีแค่ทางเลือกแบบ
curl | bashแล้วลุ้นเอาเอง หรือไม่ก็ README ที่บอกให้ติดตั้ง dependency ที่ขาดอีก 3 ตัวพร้อมขั้นตอน manual 12 ขั้น Nix? ให้ความรู้สึกว่าเป็นตัวเลือกที่ใช้ได้เฉพาะคนที่ก้าวข้ามเวลา พื้นที่ และคู่มือ Nix ไปแล้วเท่านั้น Docker? ถ้าคุณคิดว่าการดาวน์โหลด Linux distribution มาเพื่อรันsedแค่ครั้งเดียวเป็นเรื่องสมเหตุสมผล ก็โอเคเลย น่าจะต้องมีจุดกึ่งกลางที่เรียบง่าย เป็นแบบ declarative และใครก็ใช้ได้จริงเป็นเทรนด์ที่เจ๋งมากจริง ๆ และรู้สึกว่ากำลังแพร่หลายขึ้นเรื่อย ๆ เจอครั้งแรกจากบล็อกของ simonw และไปดูรายละเอียดเพิ่มใน โพสต์บล็อกของ simonwillison เมื่อเดือนมีนาคมปีนี้ก็มี การถกเถียงบน Hacker News จากบทความบล็อกอีกชิ้นด้วย อยากให้เทรนด์นี้อยู่บนหน้าแรกนาน ๆ เพื่อให้คนรู้จักมากขึ้น
ลองใช้ uv กับโปรเจ็กต์เล็ก ๆ แล้วประสบการณ์ดีมาก การใช้
uv runกับuv tool run(uvx) ทำให้ติดตั้งและรันสคริปต์ Python จาก GitHub บน VM ได้ง่ายสุด ๆ ไม่ต้องgit clone, ไม่ต้องสร้างหรือเข้าvenv, และไม่ต้องpip installที่สำคัญคือ uv เร็วมากจนตอนแรกนึกว่ามีอะไรผิดพลาด ทั้งที่จริงแล้วเร็วกว่า pip 10 เท่า แค่ตัวเครื่องมือกับเอกสารยังดูไม่สมบูรณ์อยู่บ้าง แต่ด้วยความล้ำและความใช้งานได้จริงระดับนี้ก็ถือว่าใช้ได้สบาย--helpเสียอีกฝั่ง Rust ก็พัฒนาแนวคิด shell script แบบไฟล์เดียวคล้าย ๆ กันอยู่เหมือนกัน เดิมทีเคยเห็นแนวทางนี้ใน Rust เป็นที่แรก โดยรองรับการรันไฟล์เดียวพร้อมจัดการ dependency อยากให้แพตเทิร์นนี้เกิดขึ้นในภาษาอื่น ๆ มากขึ้น เพราะมีประโยชน์มากสำหรับการแชร์ผ่าน gist หรือเขียนเครื่องมือเล็ก ๆ แบบรวดเร็ว ดู เอกสาร cargo-script RFC ได้ด้วย
เวลาใช้
uv run --scriptแล้วฝัง metadata ไว้ในสคริปต์ จะรู้สึกว่าเปิด Python REPL จากสคริปต์โดยตรงเพื่อแก้และทดสอบไม่ค่อยสะดวกเท่าไร ตัวอย่างเช่นต้องทำแบบนี้เลยหวังว่าจะมีวิธีที่กระชับกว่านี้ เช่นถ้าทำได้แบบนี้จะดีมาก
แต่ในทางปฏิบัติ ถ้ารันแบบด้านล่างก็เข้า Python และสภาพแวดล้อม
venvที่ตรงกับสคริปต์ได้ทันทีแค่ต้องรันสคริปต์สักครั้งก่อนเพื่อสร้าง environment
--interactiveลงในสคริปต์ให้เป็นตัวเลือก CLI ได้ ปกติมักเขียน CLI เล็ก ๆ ด้วย Typer ในลักษณะนี้บ่อย ใน dev script ก็เคยใช้แฟลก--sqlเพื่อเข้า DuckDB SQL REPL ด้วยถ้าใช้ conda ก็สามารถทำ shell wrapper สำหรับสคริปต์ Python ที่ activate environment โดยตรงได้ เขียนประมาณนี้
แต่ก็เป็นแนวทางที่ไม่ได้แยกตัวเป็นอิสระเหมือนสไตล์ PEP 723
หลังจากเห็นเธรด HN เมื่อวานกับวันนี้ ก็เลยตัดสินใจลอง uv เป็นครั้งแรก และประทับใจมากกับความเร็วและการจัดการ dependency ที่ง่าย ถ้าเอกสารทางการดีขึ้นก็น่าจะยิ่งดี โดยเฉพาะถ้ามีคู่มือย้ายจาก workflow แบบ requirements.txt มาเป็น uv จะสะดวกมาก เรื่องการกำหนดเวอร์ชัน Python รายโปรเจ็กต์ก็ดูชวนสับสนอยู่เหมือนกัน เพราะมีทั้ง
.python-versionและpyproject.tomlให้กำหนดrequires-versionในpyproject.tomlหมายถึงช่วงเวอร์ชันที่รับประกันว่าเข้ากันได้ ส่วน.python-versionใช้ระบุเวอร์ชันเฉพาะที่จะใช้พัฒนา ตอนสร้างด้วย uv init ใหม่ ๆ มันอาจดูเหมือนกัน แต่พอเวลาผ่านไปrequires-versionมักจะกลายเป็นเวอร์ชันขั้นต่ำที่รองรับ ซึ่งต่ำกว่า.python-versionrequires-versionยังเข้าไปอยู่ใน package metadata และมีผลต่อการแก้ dependency ของคนอื่นที่จะนำแพ็กเกจที่คุณปล่อยไปใช้ด้วย เช่น v1 ยังรองรับ Python เวอร์ชันเก่า แต่ v2 ไม่รองรับแล้ว เป็นต้นnpm updateหรือdotnet restoreแต่venvยังทำงานได้ไม่มีปัญหา ในขณะที่ uv เวลาสลับแพลตฟอร์มกลับรู้สึกว่ายุ่งยากกว่าและต้องล้างอะไรเองมากกว่าpyproject.tomlมีไว้เพื่ออธิบาย environment ที่ต้องใช้เวลาแชร์โค้ดให้ผู้พัฒนาหรือผู้ใช้ภายนอก โดยไม่ได้เกี่ยวกับ uv โดยตรง เวลาสร้างแพ็กเกจสำหรับ PyPI ก็ใช้ระบุว่าต้องการ environment แบบไหน และกำหนดช่วงเวอร์ชันเพื่อให้คนอื่นนำโค้ดไปใช้ซ้ำได้กว้างขึ้น ส่วน.python-versionนั้น uv ใช้อ้างอิงเฉพาะตอนเซ็ตอัป development environment ของฉันเท่านั้น ถ้ามี environment ที่เตรียมไว้ล่วงหน้าอยู่แล้ว ก็ไม่จำเป็นต้องตั้งค่าใหม่ก็ได้ uv ยังไม่ใช่ official build backend แต่กำลังเตรียมฟีเจอร์นั้นอยู่ (issue #3957).python-versionคงมีไว้เพื่อความเข้ากันได้กับเครื่องมืออื่นที่ไม่มี TOML parserเคยมีประสบการณ์อยากทำเครื่องมือที่ให้สคริปต์ Python ติดตั้ง dependency เองได้อัตโนมัติ (ตั้งใจให้ทำงานคล้าย uvx แต่ขอแค่มี Python ก็ใช้งานได้) แต่ข้อเสียคือจำเป็นต้องใส่บรรทัดแปลก ๆ หลายบรรทัดไว้ต้นสคริปต์ ถ้าสนใจก็ปล่อยไว้บน PyPI ในชื่อ pysolate
มีข้อความสไตล์ Grace Hopper ที่ได้แรงบันดาลใจจาก COBOL มองว่าทุกโปรแกรม Python ควรมีการกำหนด ENVIRONMENT division เพื่อระบุสภาพแวดล้อมที่ใช้คอมไพล์และรันอย่างชัดเจน รวมถึงข้อกำหนดด้านฮาร์ดแวร์และซอฟต์แวร์ และเชื่อว่าโครงสร้างแบบนี้จะมีผลสำคัญอย่างยิ่งต่อการทำให้โปรแกรมพกพาได้ดีขึ้นข้ามหลายระบบ