zipapp --- Quản lý kho lưu trữ zip Python có thể thực thi được

Added in version 3.5.

Source code: Lib/zipapp.py


Mô-đun này cung cấp các công cụ để quản lý việc tạo tệp zip chứa mã Python, có thể là executed directly by the Python interpreter. Mô-đun này cung cấp cả Giao diện dòng lệnhPython API.

Ví dụ cơ bản

Ví dụ sau đây cho thấy cách Giao diện dòng lệnh có thể được sử dụng để tạo một kho lưu trữ thực thi từ một thư mục chứa mã Python. Khi chạy, kho lưu trữ sẽ thực thi chức năng main từ mô-đun myapp trong kho lưu trữ.

$ python -m zipapp myapp -m "myapp:main"
$ trăn myapp.pyz
<đầu ra từ ứng dụng của tôi>

Giao diện dòng lệnh

Khi được gọi là một chương trình từ dòng lệnh, biểu mẫu sau được sử dụng:

$ python -m nguồn zipapp [tùy chọn]

Nếu source là một thư mục, thao tác này sẽ tạo một kho lưu trữ từ nội dung của source. Nếu source là một tệp thì nó phải là một tệp lưu trữ và nó sẽ được sao chép vào kho lưu trữ đích (hoặc nội dung của dòng shebang của nó sẽ được hiển thị nếu tùy chọn --info được chỉ định).

Các tùy chọn sau đây được hiểu:

-o <output>, --output=<output>

Ghi đầu ra vào một tệp có tên output. Nếu tùy chọn này không được chỉ định, tên tệp đầu ra sẽ giống với source đầu vào, với phần mở rộng .pyz được thêm vào. Nếu tên tệp rõ ràng được cung cấp, nó sẽ được sử dụng nguyên trạng (vì vậy nên bao gồm phần mở rộng .pyz nếu được yêu cầu).

Tên tệp đầu ra phải được chỉ định nếu source là một kho lưu trữ (và trong trường hợp đó, output không được giống với source).

-p <interpreter>, --python=<interpreter>

Thêm dòng #! vào kho lưu trữ chỉ định interpreter làm lệnh để chạy. Ngoài ra, trên POSIX, hãy làm cho tệp lưu trữ có thể thực thi được. Mặc định là không ghi dòng #! và không làm cho tệp có thể thực thi được.

-m <mainfn>, --main=<mainfn>

Viết tệp __main__.py vào kho lưu trữ thực thi mainfn. Đối số mainfn phải có dạng "pkg.mod:fn", trong đó "pkg.mod" là gói/mô-đun trong kho lưu trữ và "fn" là thành phần có thể gọi được trong mô-đun đã cho. Tệp __main__.py sẽ thực thi lệnh gọi đó.

Không thể chỉ định --main khi sao chép kho lưu trữ.

-c, --compress

Nén file bằng phương pháp giảm phát, giảm kích thước file đầu ra. Theo mặc định, các tập tin được lưu trữ không nén trong kho lưu trữ.

--compress không có tác dụng khi sao chép kho lưu trữ.

Added in version 3.7.

--info

Hiển thị trình thông dịch được nhúng trong kho lưu trữ nhằm mục đích chẩn đoán. Trong trường hợp này, mọi tùy chọn khác đều bị bỏ qua và SOURCE phải là một kho lưu trữ chứ không phải một thư mục.

-h, --help

In một thông báo sử dụng ngắn và thoát.

Python API

Mô-đun xác định hai chức năng tiện lợi:

zipapp.create_archive(source, target=None, interpreter=None, main=None, filter=None, compressed=False)

Tạo kho lưu trữ ứng dụng từ source. Nguồn có thể là một trong những nguồn sau:

  • Tên của một thư mục hoặc path-like object đề cập đến một thư mục, trong trường hợp đó một kho lưu trữ ứng dụng mới sẽ được tạo từ nội dung của thư mục đó.

  • Tên của tệp lưu trữ ứng dụng hiện có hoặc path-like object đề cập đến một tệp như vậy, trong trường hợp đó tệp được sao chép vào đích (sửa đổi nó để phản ánh giá trị được cung cấp cho đối số interpreter). Tên tệp phải bao gồm phần mở rộng .pyz, nếu được yêu cầu.

  • Một đối tượng tệp mở để đọc ở chế độ byte. Nội dung của tệp phải là kho lưu trữ ứng dụng và đối tượng tệp được coi là được đặt ở đầu kho lưu trữ.

Đối số target xác định nơi lưu trữ kết quả sẽ được ghi:

  • Nếu đó là tên của một tệp hoặc path-like object, kho lưu trữ sẽ được ghi vào tệp đó.

  • Nếu đó là một đối tượng tệp đang mở, kho lưu trữ sẽ được ghi vào đối tượng tệp đó, đối tượng này phải được mở để ghi ở chế độ byte.

  • Nếu mục tiêu bị bỏ qua (hoặc None), nguồn phải là một thư mục và mục tiêu sẽ là một tệp có cùng tên với nguồn, có thêm phần mở rộng .pyz.

Đối số interpreter chỉ định tên của trình thông dịch Python mà kho lưu trữ sẽ được thực thi. Nó được viết dưới dạng dòng "shebang" ở đầu kho lưu trữ. Trên POSIX, điều này sẽ được HĐH giải thích và trên Windows, nó sẽ được trình khởi chạy Python xử lý. Việc bỏ qua interpreter sẽ không có dòng shebang nào được viết. Nếu một trình thông dịch được chỉ định và mục tiêu là tên tệp thì bit thực thi của tệp đích sẽ được đặt.

Đối số main chỉ định tên của một chương trình có thể gọi được sẽ được sử dụng làm chương trình chính cho kho lưu trữ. Nó chỉ có thể được chỉ định nếu nguồn là một thư mục và nguồn chưa chứa tệp __main__.py. Đối số main phải có dạng "pkg.module:callable" và kho lưu trữ sẽ được chạy bằng cách nhập "pkg.module" và thực thi lệnh gọi đã cho mà không có đối số. Sẽ là lỗi nếu bỏ qua main nếu nguồn là một thư mục và không chứa tệp __main__.py, nếu không thì kho lưu trữ kết quả sẽ không thể thực thi được.

Đối số filter tùy chọn chỉ định hàm gọi lại được truyền đối tượng Đường dẫn biểu thị đường dẫn đến tệp đang được thêm vào (liên quan đến thư mục nguồn). Nó sẽ trả về True nếu tệp được thêm vào.

Đối số compressed tùy chọn xác định xem tệp có được nén hay không. Nếu được đặt thành True, các tệp trong kho lưu trữ sẽ được nén bằng phương pháp giảm phát; nếu không, các tập tin sẽ được lưu trữ không nén. Đối số này không có hiệu lực khi sao chép một kho lưu trữ hiện có.

Nếu một đối tượng tệp được chỉ định cho source hoặc target, thì người gọi có trách nhiệm đóng nó sau khi gọi create_archive.

Khi sao chép một kho lưu trữ hiện có, các đối tượng tệp được cung cấp chỉ cần các phương thức readreadline hoặc write. Khi tạo một kho lưu trữ từ một thư mục, nếu mục tiêu là một đối tượng tệp thì nó sẽ được chuyển đến lớp zipfile.ZipFile và phải cung cấp các phương thức mà lớp đó cần.

Thay đổi trong phiên bản 3.7: Đã thêm thông số filtercompressed.

zipapp.get_interpreter(archive)

Trả về trình thông dịch được chỉ định trong dòng #! khi bắt đầu kho lưu trữ. Nếu không có dòng #! thì trả về None. Đối số archive có thể là tên tệp hoặc đối tượng giống như tệp mở để đọc ở chế độ byte. Nó được cho là ở đầu kho lưu trữ.

Ví dụ

Đóng gói một thư mục vào kho lưu trữ và chạy nó.

$ python -m zipapp myapp
$ trăn myapp.pyz
<đầu ra từ ứng dụng của tôi>

Điều tương tự có thể được thực hiện bằng cách sử dụng hàm create_archive():

>>> nhập zipapp
>>> zipapp.create_archive('myapp', 'myapp.pyz')

Để làm cho ứng dụng có thể thực thi trực tiếp trên POSIX, hãy chỉ định trình thông dịch sẽ sử dụng.

$ python -m zipapp myapp -p "/usr/bin/env python"
$ ./myapp.pyz
<đầu ra từ ứng dụng của tôi>

Để thay thế dòng Shebang trên kho lưu trữ hiện có, hãy tạo một kho lưu trữ đã sửa đổi bằng hàm create_archive()

>>> nhập zipapp
>>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3')

Để cập nhật tệp tại chỗ, hãy thực hiện thay thế trong bộ nhớ bằng cách sử dụng đối tượng BytesIO, sau đó ghi đè lên nguồn. Lưu ý rằng khi ghi đè một tập tin tại chỗ có nguy cơ xảy ra lỗi dẫn đến mất tập tin gốc. Mã này không bảo vệ khỏi những lỗi như vậy nhưng mã sản xuất sẽ làm như vậy. Ngoài ra, phương pháp này sẽ chỉ hoạt động nếu kho lưu trữ vừa với bộ nhớ

>>> nhập zipapp
>>> nhập io
>>> temp = io.BytesIO()
>>> zipapp.create_archive('myapp.pyz', temp, '/usr/bin/python2')
>>> với open('myapp.pyz', 'wb')  f:
>>> f.write(temp.getvalue())

Chỉ định thông dịch viên

Lưu ý rằng nếu bạn chỉ định một trình thông dịch và sau đó phân phối kho lưu trữ ứng dụng của mình, bạn cần đảm bảo rằng trình thông dịch được sử dụng có thể mang theo được. Trình khởi chạy Python dành cho Windows hỗ trợ hầu hết các dạng dòng POSIX #! phổ biến, nhưng có những vấn đề khác cần xem xét:

  • Nếu bạn sử dụng "/usr/bin/env python" (hoặc các dạng khác của lệnh "python", chẳng hạn như "/usr/bin/python"), bạn cần cân nhắc rằng người dùng của bạn có thể có Python 2 hoặc Python 3 làm mặc định và viết mã của bạn để hoạt động trong cả hai phiên bản.

  • Nếu bạn sử dụng một phiên bản rõ ràng, chẳng hạn như "/usr/bin/env python3", ứng dụng của bạn sẽ không hoạt động đối với những người dùng không có phiên bản đó. (Đây có thể là điều bạn muốn nếu bạn chưa làm cho mã của mình tương thích với Python 2).

  • Không có cách nào để nói "python X.Y trở lên", vì vậy hãy cẩn thận khi sử dụng phiên bản chính xác như "/usr/bin/env python3.4" vì bạn sẽ cần thay đổi dòng Shebang của mình cho người dùng Python 3.5 chẳng hạn.

Thông thường, bạn nên sử dụng "/usr/bin/env python2" hoặc "/usr/bin/env python3", tùy thuộc vào việc mã của bạn được viết cho Python 2 hay 3.

Tạo ứng dụng độc lập với zipapp

Sử dụng mô-đun zipapp, có thể tạo các chương trình Python độc lập, có thể được phân phối cho người dùng cuối, những người chỉ cần cài đặt phiên bản Python phù hợp trên hệ thống của họ. Chìa khóa để thực hiện việc này là gộp tất cả các phần phụ thuộc của ứng dụng vào kho lưu trữ, cùng với mã ứng dụng.

Các bước để tạo một kho lưu trữ độc lập như sau:

  1. Tạo ứng dụng của bạn trong một thư mục như bình thường, do đó bạn có một thư mục myapp chứa tệp __main__.py và bất kỳ mã ứng dụng hỗ trợ nào.

  2. Cài đặt tất cả các phần phụ thuộc của ứng dụng của bạn vào thư mục myapp, sử dụng pip:

    $ python -m pip cài đặt -r require.txt --target myapp
    

    (điều này giả định rằng bạn có các yêu cầu dự án của mình trong tệp requirements.txt - nếu không, bạn chỉ có thể liệt kê các phần phụ thuộc theo cách thủ công trên dòng lệnh pip).

  3. Đóng gói ứng dụng bằng cách sử dụng:

    $ python -m zipapp -p "thông dịch viên" myapp
    

Điều này sẽ tạo ra một tệp thực thi độc lập, có thể chạy trên bất kỳ máy nào có sẵn trình thông dịch thích hợp. Xem Chỉ định thông dịch viên để biết chi tiết. Nó có thể được chuyển đến người dùng dưới dạng một tệp duy nhất.

Trên Unix, tệp myapp.pyz có thể thực thi được. Bạn có thể đổi tên tệp để xóa phần mở rộng .pyz nếu bạn thích tên lệnh "đơn giản". Trên Windows, tệp myapp.pyz[w] có thể thực thi được nhờ trình thông dịch Python đăng ký phần mở rộng tệp .pyz.pyzw khi cài đặt.

Hãy cẩn thận

Nếu ứng dụng của bạn phụ thuộc vào gói có phần mở rộng C, thì gói đó không thể chạy từ tệp zip (đây là giới hạn của hệ điều hành, vì mã thực thi phải có trong hệ thống tệp để trình tải hệ điều hành tải nó). Trong trường hợp này, bạn có thể loại trừ phần phụ thuộc đó khỏi tệp zip và yêu cầu người dùng cài đặt nó hoặc gửi nó cùng với tệp zip và thêm mã vào __main__.py để bao gồm thư mục chứa mô-đun đã giải nén trong sys.path. Trong trường hợp này, bạn cần đảm bảo gửi các tệp nhị phân thích hợp cho (các) kiến ​​trúc đích của mình (và có thể chọn đúng phiên bản để thêm vào sys.path khi chạy, dựa trên máy của người dùng).

Định dạng lưu trữ ứng dụng Python Zip

Python đã có thể thực thi các tệp zip chứa tệp __main__.py kể từ phiên bản 2.6. Để được Python thực thi, kho lưu trữ ứng dụng chỉ cần là một tệp zip tiêu chuẩn chứa tệp __main__.py sẽ được chạy làm điểm vào cho ứng dụng. Như thường lệ đối với bất kỳ tập lệnh Python nào, phần gốc của tập lệnh (trong trường hợp này là tệp zip) sẽ được đặt trên sys.path và do đó có thể nhập thêm các mô-đun từ tệp zip.

Định dạng tệp zip cho phép dữ liệu tùy ý được thêm vào trước tệp zip. Định dạng ứng dụng zip sử dụng khả năng này để thêm dòng "shebang" POSIX tiêu chuẩn vào tệp (#!/path/to/interpreter).

Do đó, về mặt hình thức, định dạng ứng dụng zip Python là:

  1. Một dòng Shebang tùy chọn, chứa các ký tự b'#!', theo sau là tên trình thông dịch và sau đó là ký tự dòng mới (b'\n'). Tên trình thông dịch có thể là bất cứ thứ gì được chấp nhận đối với quá trình xử lý "shebang" của hệ điều hành hoặc trình khởi chạy Python trên Windows. Trình thông dịch phải được mã hóa bằng UTF-8 trên Windows và sys.getfilesystemencoding() trên POSIX.

  2. Dữ liệu zipfile tiêu chuẩn, do mô-đun zipfile tạo ra. Nội dung tệp zip must bao gồm một tệp có tên __main__.py (phải nằm trong "gốc" của tệp zip - tức là nó không thể nằm trong thư mục con). Dữ liệu zipfile có thể được nén hoặc không nén.

Nếu kho lưu trữ ứng dụng có dòng Shebang, nó có thể có bit thực thi được đặt trên hệ thống POSIX để cho phép nó được thực thi trực tiếp.

Không có yêu cầu nào về việc sử dụng các công cụ trong mô-đun này để tạo kho lưu trữ ứng dụng - mô-đun này rất tiện lợi, nhưng các kho lưu trữ ở định dạng trên được tạo bằng bất kỳ phương tiện nào đều được Python chấp nhận.