Tại sao bình CLI được đề xuất trên Flask.run?


13

Trong Flask 0.11, flaskCLI đã được giới thiệu. Cả hai tài liệu và trạng thái thay đổi này được khuyến khích.

Tài liệu máy chủ phát triển :

Bắt đầu với Flask 0.11, có nhiều cách tích hợp để chạy máy chủ phát triển. Một trong những tốt nhất là bình tiện ích dòng lệnh nhưng bạn cũng có thể tiếp tục sử dụng Flask.run()phương pháp.

Dòng lệnh

Các bình kịch bản dòng lệnh (Command Line Interface) được khuyến khích mạnh mẽ cho sự phát triển vì nó cung cấp một trải nghiệm tải lại vượt trội do cách nó tải các ứng dụng. Cách sử dụng cơ bản là như thế này:

$ export FLASK_APP=my_application
$ export FLASK_DEBUG=1
$ flask run

Thay đổi :

  • Đã thêm flaskflask.climô-đun để khởi động máy chủ gỡ lỗi cục bộ thông qua hệ thống CLI nhấp. Điều này được khuyến nghị so với flask.run()phương pháp cũ vì nó hoạt động nhanh hơn và đáng tin cậy hơn do một thiết kế khác và cũng thay thế Flask-Script.

Cho đến nay tôi đã không nhận thấy "trải nghiệm tải lại vượt trội" này. Tôi không thấy điểm sử dụng CLI qua tập lệnh tùy chỉnh.

Nếu sử dụng Flask.run, tôi chỉ cần viết một tệp python:

#!/usr/bin/env python3
from my_app import app


if __name__ == '__main__':
    app.run(debug=True)

Nếu sử dụng CLI, người ta sẽ phải chỉ định các biến môi trường. Trong các tài liệu CLI được tuyên bố rằng điều này có thể được tích hợp trong activatetập lệnh của virtualenvwrapper. Cá nhân tôi coi đây là một phần của ứng dụng và nghĩ rằng nó nên được kiểm soát phiên bản. Than ôi, một kịch bản shell là cần thiết:

#!/usr/bin/env bash
export FLASK_APP=my_app:app
export FLASK_DEBUG=1

flask run

Tất nhiên, điều này sẽ được kèm theo một tập lệnh bat bổ sung ngay khi bất kỳ người dùng Windows nào bắt đầu cộng tác.

Ngoài ra tùy chọn đầu tiên cho phép thiết lập được viết bằng Python trước khi bắt đầu ứng dụng thực tế.

Điều này cho phép ví dụ

  • để phân tích các đối số dòng lệnh trong Python
  • để thiết lập đăng nhập trước khi chạy ứng dụng

Họ dường như quảng bá rằng có thể thêm các lệnh tùy chỉnh. Tôi không thấy lý do tại sao điều này tốt hơn là viết các tập lệnh Python đơn giản, tùy ý hiển thị thông qua các điểm nhập cảnh.

Ví dụ đầu ra ghi nhật ký khi sử dụng bộ ghi nhật ký được cấu hình bằng tập lệnh chạy Python:

$ ./run.py 
   DEBUG 21:51:22 main.py:95) Configured logging
    INFO 21:51:22 _internal.py:87)  * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    INFO 21:51:22 _internal.py:87)  * Restarting with inotify reloader
   DEBUG 21:51:22 main.py:95) Configured logging
 WARNING 21:51:22 _internal.py:87)  * Debugger is active!
    INFO 21:51:22 _internal.py:87)  * Debugger pin code: 263-225-431
   DEBUG 21:51:25 inotify_buffer.py:61) in-event <InotifyEvent: src_path=b'my_app/main.py', wd=272, mask=IN_MODIFY, cookie=0, name=b'main.py'>
   DEBUG 21:51:25 inotify_buffer.py:61) in-event <InotifyEvent: src_path=b'my_app/main.py', wd=272, mask=IN_MODIFY, cookie=0, name=b'main.py'>
    INFO 21:51:25 _internal.py:87)  * Detected change in 'my_app/main.py', reloading
    INFO 21:51:26 _internal.py:87)  * Restarting with inotify reloader
   DEBUG 21:51:26 main.py:95) Configured logging
 WARNING 21:51:26 _internal.py:87)  * Debugger is active!
    INFO 21:51:26 _internal.py:87)  * Debugger pin code: 263-225-431

Ví dụ đầu ra ghi nhật ký khi sử dụng bộ ghi nhật ký được cấu hình bằng CLI:, lưu ý rằng bộ ghi nhật ký gốc không thể được thiết lập đủ sớm trong quy trình.

$ ./run.sh 
 * Serving Flask app "appsemble.api.main:app"
 * Forcing debug mode on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with inotify reloader
   DEBUG 21:51:33 main.py:95) Configured logging
 * Debugger is active!
 * Debugger pin code: 187-758-498
   DEBUG 21:51:34 main.py:95) Configured logging
   DEBUG 21:51:37 inotify_buffer.py:61) in-event <InotifyEvent: src_path=b'my_app/main.py', wd=272, mask=IN_MODIFY, cookie=0, name=b'main.py'>
   DEBUG 21:51:37 inotify_buffer.py:61) in-event <InotifyEvent: src_path=b'my_app/main.py', wd=272, mask=IN_MODIFY, cookie=0, name=b'main.py'>
 * Detected change in 'my_app/main.py', reloading
    INFO 21:51:37 _internal.py:87)  * Detected change in 'my_app/main.py', reloading
 * Restarting with inotify reloader
    INFO 21:51:38 _internal.py:87)  * Restarting with inotify reloader
 * Debugger is active!
 * Debugger pin code: 187-758-498
   DEBUG 21:51:38 main.py:95) Configured logging

Câu hỏi thực tế của tôi chỉ đơn giản là:

Tại sao bình CLI được đề nghị hơn Flask.run?

Câu trả lời:


11

Trong tài liệu máy chủ phát triển, chúng nêu có vấn đề với việc gọi run () và tự động tải lại mã:

Điều này hoạt động tốt cho trường hợp phổ biến nhưng nó không hoạt động tốt cho sự phát triển, đó là lý do tại sao từ Flask 0.11 trở đi, phương pháp bình được khuyên dùng. Lý do cho điều này là do cơ chế tải lại hoạt động như thế nào, có một số tác dụng phụ kỳ quái (như thực thi mã nhất định hai lần, đôi khi bị lỗi mà không có thông báo hoặc chết khi xảy ra lỗi cú pháp hoặc nhập).

Họ tuyên bố CLI không gặp phải vấn đề này.

Cam kết đầu tiên dường như chạm đến vấn đề này là: https://github.com/pallets/flask/commit/3bdb90f06b9d3167320180d4a5055dcd949bf72f

Và ở đó Armin Ronacher đã viết:

Không nên sử dụng chức năng này để phát triển với tải lại tự động vì điều này được hỗ trợ rất tệ. Thay vào đó, bạn nên sử dụng sự hỗ trợ flaskcủa tập lệnh dòng lệnh runserver.

Như Aaron Hall đã đề cập, có vẻ như việc sử dụng run () có thể gặp vấn đề do thực tế là tất cả các đối tượng là các thể hiện của các lớp được thay thế sẽ không được cung cấp lại và bất cứ khi nào một mô-đun được tải lại, mô-đun nó nhập khẩu cũng không tải lại.

Các chi tiết về điều này có thể được tìm thấy cho Python 3 tại: https://docs.python.org/3/l Library / imllib.html?highlight=importlib#module-importlib

Nó nói:

Như với tất cả các đối tượng khác trong Python, các đối tượng cũ chỉ được lấy lại sau khi số tham chiếu của chúng giảm xuống không.

Các tham chiếu khác đến các đối tượng cũ (chẳng hạn như tên bên ngoài mô-đun) không được bật lại để tham chiếu đến các đối tượng mới và phải được cập nhật trong mỗi không gian tên nơi chúng xảy ra nếu muốn.

Khi một mô-đun được tải lại, từ điển của nó (chứa các biến toàn cục của mô-đun) được giữ lại. Định nghĩa lại tên sẽ ghi đè các định nghĩa cũ, vì vậy đây thường không phải là vấn đề. Nếu phiên bản mới của mô-đun không xác định tên được xác định bởi phiên bản cũ, định nghĩa cũ vẫn còn.

Vì vậy, bằng cách tạo ra một quy trình mới và giết chết quy trình cũ, bạn tự nhiên loại bỏ tất cả các tài liệu tham khảo lỗi thời.

Ngoài ra, CLI của Flask sử dụng mô-đun 'nhấp chuột', giúp dễ dàng thêm các lệnh tùy chỉnh, nhưng quan trọng nhất, bên cạnh việc sửa lỗi tải lại, CLI cung cấp một cách chuẩn hóa để chạy các ứng dụng và thêm các lệnh tùy chỉnh. Điều này nghe có vẻ như là một điều rất tốt, bởi vì nó làm cho Flask trở nên dễ chuyển đổi hơn giữa các nhóm và ứng dụng khác nhau, thay vì có nhiều cách để làm điều tương tự.

Có vẻ như là một cách chính hãng để làm cho Flask phù hợp hơn với Zen của Python:

Nên có một-- và tốt nhất là chỉ có một cách rõ ràng để làm điều đó.


2
Đây là những gì tôi nghĩ Armin có nghĩa là "được hỗ trợ rất tệ": Trong Python, tải lại một mô-đun không tải lại các mô-đun mà mô-đun nhập vào, cũng không liên kết lại các tên trong các mô-đun khác để trỏ đến các đối tượng cũ từ mô-đun mới - quá nóng để hoán đổi một mô-đun mới vào cùng một quy trình là vấn đề. Tốt hơn hết là bạn nên bắt đầu một quy trình mới khi bạn muốn thay đổi mã.
Aaron Hall

Bây giờ bạn đề cập đến nó, tôi nhớ lại hành vi bạn mô tả, cảm ơn bạn đã làm rõ! Tôi sẽ chỉnh sửa câu trả lời cho phù hợp.
Martin Jungblut Schreiner

ok, cộng 1 cho trích dẫn tôi :)
Aaron Hall

Việc bổ sung từ Aaron Hall đã làm rõ nó cho tôi. Cảm ơn. :)
Remco Haszing

7
Tại sao chúng ta phải sử dụng biến môi trường FLASK_APP? Đó có phải là nội tại để làm việc này? Tôi tò mò tại sao flask runkhông chấp nhận giống như một cuộc tranh cãi, điều này sẽ giúp việc đưa người mới lên tàu dễ dàng hơn. Cảm ơn bạn.
John Wheeler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.