Khai thác script Python với uv và PEP 723
(cottongeeks.com)- Trình quản lý gói uv và PEP 723 giúp có thể chạy script Python mà không gặp vấn đề về phụ thuộc
- Tính năng uvx tự động tạo môi trường ảo dùng tạm, giải quyết sự bất tiện trong việc thiết lập môi trường
- Khi nhúng metadata PEP 723 vào tệp Python, việc tự động chạy script và quản lý gói trở nên thuận tiện hơn
- Với ví dụ script thực thi, có thể nhanh chóng triển khai và phát hành chương trình trích xuất phụ đề YouTube
- Nhờ đó, giờ đây Python cũng có thể viết tệp thực thi đơn lẻ gọn gàng, giúp khả năng tận dụng script được cải thiện đáng kể
Tổng quan
- Trước đây, khi chạy các "script dùng một lần (one-off)" trong Python, luôn phải trải qua bước thiết lập môi trường và cài gói mỗi lần, nhưng sự bất tiện đó đã biến mất nhờ uv và PEP 723
- uv là trình quản lý gói và dự án Python tốc độ cao được phát triển bằng Rust; cùng với tính năng mới uvx, nó xử lý việc thiết lập môi trường ảo dùng tạm, tự động cài gói và liên kết phiên bản Python rất nhanh và đơn giản
Ưu điểm của uv và uvx
- Tính năng uvx hoạt động tương tự npx trong hệ sinh thái Nodejs, nhanh chóng tạo môi trường để chạy gói Python được chỉ định (ví dụ: ruff)
- Tận dụng disposable virtual environment dưới dạng bộ nhớ đệm để mang lại khả năng thực thi nhanh mà không phát sinh overhead
- Việc thiết lập môi trường và cài phụ thuộc được thực hiện chỉ bằng một dòng lệnh, nên lập trình viên không cần tự quản lý cấu hình môi trường riêng
Giới thiệu và cách dùng PEP 723
- PEP 723 định nghĩa tiêu chuẩn cho phép đưa metadata về phụ thuộc và môi trường vào đầu script Python
- Ví dụ: có thể khai báo
requires-python,dependenciesở phần đầu mã - Các công cụ bên ngoài nhận diện được điều này (như uv) sẽ tự động xử lý cài đặt, thiết lập môi trường và thực thi dựa trên thông tin được viết ngay trong tệp script
Kết hợp uv và PEP 723
- Khi viết metadata tương ứng ở đầu một tệp Python mẫu và chạy bằng lệnh
uv run, tất cả gói cần thiết sẽ được tự động cài đặt ngay, phiên bản Python được chỉ định cũng được thiết lập trước khi mã được thực thi - Mã ví dụ gọi một API trên Internet (danh sách PEP) và in ra kết quả. Có thể chạy chỉ bằng một dòng lệnh mà không cần cài thêm gói hay cấu hình môi trường
Ví dụ thực tế: script phụ đề YouTube
- Cung cấp ví dụ script Python có thêm shebang(
#!/usr/bin/env -S uv run --script) và metadata PEP 723 - Tự động cài các gói bên ngoài như
youtube-transcript-apivà tự động thiết lập môi trường ảo - Người dùng chỉ cần truyền URL hoặc ID video Youtube làm đối số cho tệp thực thi (
ytt), script sẽ trích xuất phụ đề và trả kết quả ngay lập tức - Sau khi cấp quyền thực thi bằng
chmod, có thể chạy dễ dàng trong terminal
Cải thiện trải nghiệm lập trình viên và mở rộng khả năng
- Trước đây, ngay cả với việc chạy script đơn giản, người ta thường ưu tiên các ngôn ngữ tạo binary thực thi đơn lẻ như Go; nhưng giờ Python cũng mang lại mức độ tiện lợi tương đương
- Sự kết hợp giữa uv và PEP 723 giúp việc chia sẻ, phát hành và tự động hóa thực thi script Python trở nên dễ dàng hơn rất nhiều
- Có thể phát triển các trường hợp sử dụng phức tạp hơn thông qua ví dụ trên Github (
cottongeeks/ytt-mcp)
2 bình luận
uv nhanh kinh khủng nên dùng rất sướng. Dạo này tôi đang dùng uv ở mọi nơi có thể.
Ý kiến trên Hacker News
Giống tác giả bài viết, dạo này tôi cũng hay tìm đến các script Python đa nền tảng dùng một lần và script cá nhân hơn là Go, nhưng vẫn thấy không hài lòng vì hệ thống kiểm tra kiểu của Python đúng là hỗn loạn; hy vọng các công cụ như ty, pyrefly sẽ cải thiện được phần nào
Giờ thì có cảm giác script Python chạy ngay ngon lành mà không còn phải khổ sở vì virtualenv nữa Tôi cũng ước phía shell script có được trải nghiệm như vậy Đóng gói, quản lý phụ thuộc và khả năng tái lập vẫn như đang ở thời kỳ đồ đá Hiện thực bây giờ vẫn là hoặc phó mặc cho số phận với
curl | bash, hoặc chỉ có một file README chứa 3 phụ thuộc bị thiếu và 12 bước thủ công Nix? Cảm giác như chỉ là lựa chọn dùng được cho những ai đã siêu thoát khỏi thời gian, không gian và cả cuốn hướng dẫn Nix Docker? Nếu thấy việc tải hẳn một bản phân phối Linux chỉ để chạy một lệnhsedlà hợp lý thì đó cũng là một lựa chọn ổn Thật sự cần một điểm trung gian đơn giản, mang tính khai báo, mà ai cũng có thể dùng dễ dàngĐây thật sự là một xu hướng rất tuyệt và có cảm giác ngày càng phổ biến hơn Tôi biết đến nó lần đầu qua blog của simonw, và có thể xem thêm ở bài blog của simonwillison Hồi tháng 3 năm nay cũng đã có thảo luận trên Hacker News về một bài blog khác Mong là xu hướng này sẽ ở lại trang chính đủ lâu để nhiều người biết đến hơn
Tôi đã thử dùng uv cho các dự án nhỏ và trải nghiệm thật sự xuất sắc Kết hợp
uv runvàuv tool run(uvx) giúp việc cài rồi chạy ngay các script Python trên GitHub trong VM trở nên cực kỳ đơn giản Không cầngit clone, không cần tạo hay chui vàovenv, cũng không cầnpip installQuan trọng hơn cả là uv nhanh đến mức ban đầu tôi còn tưởng có gì đó sai sai; thực tế thì kết quả nhanh hơn pip 10 lần Dù vậy công cụ và tài liệu vẫn còn hơi chưa hoàn thiện, nhưng với mức độ đột phá và tính thực dụng như vậy thì vẫn quá đáng để dùng--helpRust cũng đang phát triển ý tưởng shell script kiểu single-file tương tự thế này Ban đầu tôi thấy kiểu làm này ở Rust trước tiên (hỗ trợ chạy file đơn kèm quản lý phụ thuộc) Tôi hy vọng mô thức này sẽ được nhiều ngôn ngữ khác tiếp nhận hơn, vì nó cực kỳ hữu ích để chia sẻ qua gist hoặc viết các công cụ nhỏ thật nhanh Xem thêm tài liệu RFC của cargo-script
Khi dùng
uv run --script, nếu nhúng metadata vào script thì việc mở ngay Python REPL từ script để sửa và thử hơi bất tiện Ví dụ phải làm như sau,Tôi mong có cách nào ngắn gọn hơn Ví dụ nếu có thể làm như
thì sẽ là tốt nhất, nhưng trên thực tế nếu chạy như dưới đây thì có thể vào thẳng môi trường Python và
venvphù hợp với scriptTuy vậy cần chạy script ít nhất một lần để tạo môi trường
--interactivevào script để biến nó thành tùy chọn CLI Tôi thường viết các CLI nhỏ dựa trên Typer theo kiểu này Với script dev, tôi từng có trải nghiệm dùng cờ--sqlđể vào DuckDB SQL REPLNếu dùng conda, có thể kích hoạt môi trường trực tiếp trong shell wrapper cho script Python Viết như sau
Tuy nhiên, đây không phải cách tiếp cận độc lập như kiểu PEP 723
Sau khi xem thread HN hôm qua và hôm nay, tôi quyết định thử uv lần đầu, và thật sự ấn tượng với tốc độ nhanh cùng việc quản lý phụ thuộc dễ dàng Sẽ còn tốt hơn nữa nếu tài liệu chính thức được cải thiện, đặc biệt là có hướng dẫn chuyển từ workflow
requirements.txtsang uv thì sẽ tiện hơn Phần chỉ định phiên bản Python theo dự án hơi gây rối (định nghĩa ở cả.python-versionvàpyproject.toml)requires-versiontrongpyproject.tomlmang nghĩa phạm vi phiên bản được đảm bảo tương thích, còn.python-versionchỉ định phiên bản cụ thể dùng cho phát triển Khi tạo bằng uv init thì lúc đầu chúng trông có vẻ giống nhau, nhưng theo thời gian thìrequires-versionsẽ chỉ định phiên bản tối thiểu được hỗ trợ thấp hơn.python-versionrequires-versioncũng đi vào metadata của package và ảnh hưởng đến việc giải quyết phụ thuộc của người khác khi dùng package bạn phát hành Ví dụ như v1 còn hỗ trợ Python bản 3 cũ, nhưng v2 thì không nữanpm updatehoặcdotnet restore, nhưngvenvvẫn hoạt động ổn không vấn đề gì Còn uv thì khi đổi nền tảng theo kiểu này có vẻ phức tạp hơn và cần dọn dẹp thủ công nhiều hơnpyproject.toml(không riêng gì uv) nhằm mục đích định nghĩa môi trường cần thiết khi chia sẻ mã với nhà phát triển và người dùng bên ngoài Khi build package cho PyPI thì nó dùng để khai báo cần môi trường nào, và phạm vi phiên bản cũng được đặt để mở rộng mức độ tái sử dụng mã cho nhiều người Còn.python-versionchỉ để uv tham chiếu khi thiết lập môi trường phát triển của riêng tôi Nếu đã có sẵn môi trường được tạo từ trước thì không nhất thiết phải cấu hình lại uv vẫn chưa là build backend chính thức, nhưng đang chuẩn bị cho tính năng đó (issue #3957).python-versionchủ yếu là để tương thích với các công cụ khác không có TOML parserTrước đây tôi từng muốn tạo một công cụ để script Python tự cài phụ thuộc (mục tiêu là công cụ hoạt động kiểu uvx, nhưng chỉ cần có Python là chạy được) Tuy vậy nhược điểm là phải chèn nhiều dòng trông khá kỳ ở đầu script Nếu tò mò thì nó đang được phát hành trên PyPI với tên pysolate
Một kiểu thông điệp theo phong cách Grace Hopper lấy cảm hứng từ COBOL Cần có văn hóa mọi chương trình Python đều định nghĩa một ENVIRONMENT division để ghi rõ môi trường biên dịch và chạy (bao gồm cả yêu cầu phần cứng, phần mềm) Cấu trúc như vậy sẽ có tác động quyết định trong việc cải thiện tính di động của chương trình giữa nhiều hệ thống khác nhau