[英]Terminating a Python command-line script with helpful messages, pythonically
如果要處理的數據不正確,我正在編寫的腳本應返回到shell提示符並顯示一條有用的消息。 用戶應該解決標記的問題,直到腳本滿意並且不再退出並顯示錯誤消息為止。 我正在使用TTD開發腳本,因此在編寫函數之前先編寫pytest
測試。
投票最多的答案是建議通過調用sys.exit
或提高SystemExit
來編輯腳本。
功能:
def istext(file_to_test):
try:
open(file_to_test).read(512)
except UnicodeDecodeError:
sys.exit('File {} must be encoded in UTF-8 (Unicode); try converting.'.format(file_to_test))
通過了此測試(其中_non-text.png
是PNG文件,即未使用UTF-8編碼):
def test_istext():
with pytest.raises(SystemExit):
istext('_non-text.png')
但是,腳本將繼續運行,並在try/except
塊之后執行語句。
我希望腳本每次都完全退出,以便用戶可以調試數據直到正確為止,並且腳本將執行應做的工作(即處理充滿UTF-8文本文件而不是PNG的目錄) ,JPG,PPTX ...文件)。
還嘗試了:
以下代碼通過引發SystemExit
的子類異常來通過上述測試,但它也不會退出腳本:
def istext(file_to_test):
class NotUTF8Error(SystemExit): pass
try:
open(file_to_test).read(512)
except UnicodeDecodeError:
raise NotUTF8Error('File {} must be UTF-8.'.format(file_to_test))
try ... except塊用於捕獲錯誤並在內部進行處理。 您要做的是重新引發該錯誤。
def istext(file_to_test):
try:
open(file_to_test).read(512)
except UnicodeDecodeError:
print(('File {} must be encoded in UTF-8 (Unicode); try converting.'.format(file_to_test)))
raise
這將打印您的消息,然后自動重新引發您發現的錯誤。
您可能還想更改錯誤類型,而不是僅重新引發舊錯誤。 對於這種情況,您可以進一步指定加薪,例如:
raise NameError('I'm the shown error message')
您可以raise Exception from exception
語法中使用raise Exception from exception
:
class MyException(SystemExit):
pass
def istext(file_to_test):
try:
open(file_to_test).read(512)
except UnicodeDecodeError as exception:
raise MyException(f'File {file_to_test} must be encoded in UTF-8 (Unicode); try converting.') \
from exception
在這種情況下,您不會更改原始錯誤消息並添加自己的消息。
您的問題不是如何退出程序( sys.exit()
正常工作)。 您的問題是您的測試方案沒有引發UnicodeDecodeError
。
這是您的示例的簡化版本。 它按預期工作:
import pytest
import sys
def foo(n):
try:
1/n
except ZeroDivisionError as e:
sys.exit('blah')
def test_foo():
# Assertion passes.
with pytest.raises(SystemExit):
foo(0)
# Assertion fails: "DID NOT RAISE <type 'exceptions.SystemExit'>"
with pytest.raises(SystemExit):
foo(9)
在代碼中添加一些診斷打印以了解更多信息。 例如:
def istext(file_to_test):
try:
content = open(file_to_test).read(512)
# If you see this, no error occurred. Maybe your source
# file needs different content to trigger UnicodeDecodeError.
print('CONTENT len()', len(content))
except UnicodeDecodeError:
sys.exit('blah')
except Exception as e:
# Maybe some other type of error should also be handled?
...
最后,有效的方法與@ADR提出的類似,但有一個區別:我無法使上面顯示的格式化字符串語法正常工作( f'File {file_to_test} must...'
),我也無法查找字符串的f
前綴的文檔。
那么,對於(重命名的)函數,我的解決方案略遜一籌:
def is_utf8(file):
class NotUTF8Error(SystemExit): pass
try:
open(file).read(512)
except UnicodeDecodeError as e:
raise NotUTF8Error('File {} not UTF-8: convert or delete, then retry.'.format(file)) from e
通過pytest:
def test_is_utf81():
with pytest.raises(SystemExit):
is_utf8('/Users/tbaker/github/tombaker/mklists/mklists/_non-text.png')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.