예외에 정보를 추가하시겠습니까?
나는 다음과 같은 것을 달성하고 싶다.
def foo():
try:
raise IOError('Stuff ')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
e.message = e.message + 'happens at %s' % arg1
raise
bar('arg1')
Traceback...
IOError('Stuff Happens at arg1')
하지만 내가 알게 된 건
Traceback..
IOError('Stuff')
어떻게 이 일을 해낼 수 있는지 단서가 있나요?Python 2와 Python 3 둘 다 어떻게 하나요?
Python 3의 솔루션을 찾고 있는 경우는, 메뉴얼에 다음과 같이 기재되어 있습니다.
(베어)를 하는 것이 )
raise현재하기 위해)를 사용하여 할 수 .fromraise:
raise new_exc from original_exc
예:
try:
return [permission() for permission in self.permission_classes]
except TypeError as e:
raise TypeError("Make sure your view's 'permission_classes' are iterable. "
"If you use '()' to generate a set with a single element "
"make sure that there is a comma behind the one (element,).") from e
마지막에는 이렇게 보입니다.
2017-09-06 16:50:14,797 [ERROR] django.request: Internal Server Error: /v1/sendEmail/
Traceback (most recent call last):
File "venv/lib/python3.4/site-packages/rest_framework/views.py", line 275, in get_permissions
return [permission() for permission in self.permission_classes]
TypeError: 'type' object is not iterable
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
# Traceback removed...
TypeError: Make sure your view's Permission_classes are iterable. If
you use parens () to generate a set with a single element make
sure that there is a (comma,) behind the one element.
명료하지 않게 되다TypeError원래 예외를 망치지 않고 해결책을 찾기 위한 힌트와 함께 좋은 메시지로 만듭니다.
이렇게 하고 싶으니까 활자를 바꿔서foo() 필요가 bar().
def foo():
try:
raise IOError('Stuff')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
raise type(e)(e.message + ' happens at %s' % arg1)
bar('arg1')
Traceback (most recent call last):
File "test.py", line 13, in <module>
bar('arg1')
File "test.py", line 11, in bar
raise type(e)(e.message + ' happens at %s' % arg1)
IOError: Stuff happens at arg1
업데이트 1
다음은 원래 트레이스백을 보존하기 위한 약간의 수정 사항입니다.
...
def bar(arg1):
try:
foo()
except Exception as e:
import sys
raise type(e), type(e)(e.message +
' happens at %s' % arg1), sys.exc_info()[2]
bar('arg1')
Traceback (most recent call last):
File "test.py", line 16, in <module>
bar('arg1')
File "test.py", line 11, in bar
foo()
File "test.py", line 5, in foo
raise IOError('Stuff')
IOError: Stuff happens at arg1
업데이트 2
3.첫 않습니다. Python 3.x의 코드에는 Python 3.x의 코드, Python 3.x의 , Python 3.x의 코드, Python 3.x의 코드, Python 3.x의 코드, Python 3.x의 코드라는 이 포함되어 있습니다.message으로 돌리다BaseException2012년 5월 16일에 PEP 352로 변경되어 철회되었습니다(첫 업데이트는 2012년 3월 12일에 게시되었습니다).따라서 현재 Python 3.5.2에서는 트레이스백을 보존하고 기능상의 예외 유형을 하드코드하지 않기 위해 이러한 행에 따라 작업을 수행해야 합니다.bar()에는 다음과 같은행이 점에 해 주세요.
During handling of the above exception, another exception occurred:
표시되는 트레이스백메시지에 표시됩니다.
# for Python 3.x
...
def bar(arg1):
try:
foo()
except Exception as e:
import sys
raise type(e)(str(e) +
' happens at %s' % arg1).with_traceback(sys.exc_info()[2])
bar('arg1')
업데이트 3
Python 2와 Python 3 둘 다 사용할 수 있는 방법이 있는지 한 코멘터가 물었다.구문의 차이로 인해 대답은 "아니오"인 것처럼 보일 수 있지만 애드온모듈과 같이 도우미 기능을 사용하여 이를 회피할 수 있습니다.따라서 어떤 이유로 라이브러리를 사용하지 않는 경우 아래는 단순화된 독립 실행형 버전입니다.
, 음, 음, 음, 음, 음, 음, 음, 음, 음, 시, 음, 시, 시, 시, 시, 시, 시, 시, 시, 시, 시, 시, the, the, the, the, the, the, the, the,reraise()어떤 트레이스백이 발생해도 나타나는 함수입니다만, 최종 결과는 원하는 것입니다.
import sys
if sys.version_info.major < 3: # Python 2?
# Using exec avoids a SyntaxError in Python 3.
exec("""def reraise(exc_type, exc_value, exc_traceback=None):
raise exc_type, exc_value, exc_traceback""")
else:
def reraise(exc_type, exc_value, exc_traceback=None):
if exc_value is None:
exc_value = exc_type()
if exc_value.__traceback__ is not exc_traceback:
raise exc_value.with_traceback(exc_traceback)
raise exc_value
def foo():
try:
raise IOError('Stuff')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
reraise(type(e), type(e)(str(e) +
' happens at %s' % arg1), sys.exc_info()[2])
bar('arg1')
foo()를 수정하지 않거나 수정할 수 없는 경우 다음을 수행할 수 있습니다.
try:
raise IOError('stuff')
except Exception as e:
if len(e.args) >= 1:
e.args = (e.args[0] + ' happens',) + e.args[1:]
raise
이것은 Python 3의 문제를 "위 예외 처리 중 다른 예외가 발생했습니다"라는 보기 흉하고 혼란스러운 메시지 없이 해결할 수 있는 유일한 솔루션입니다.
가 있는 는, 「」라고 써 .raise eraise효과가 있을 거야
나는 지금까지의 모든 답이 마음에 들지 않는다.그들은 여전히 너무 장황한 임호이다.코드 출력과 메시지 출력 중 하나.
스택 트레이스는 소스 예외를 가리키고 있기 때문에 새로운 예외를 생성하지 않고 관련된 스택프레임 상태를 모두 포함한 원본을 다시 작성하기만 하면 됩니다.
Steve Howard가 좋은 답변을 해줬습니다. 아니, 파이톤 3만 줄여주세요.
except Exception as e:
e.args = ("Some failure state", *e.args)
raise
새로운 것은 파라미터의 확장/언패킹뿐입니다.이것에 의해, 작고 사용하기 쉬워집니다.
시험해 보세요:
foo = None
try:
try:
state = "bar"
foo.append(state)
except Exception as e:
e.args = ("Appending '"+state+"' failed", *e.args)
raise
print(foo[0]) # would raise too
except Exception as e:
e.args = ("print(foo) failed: " + str(foo), *e.args)
raise
다음과 같은 이점을 얻을 수 있습니다.
Traceback (most recent call last):
File "test.py", line 6, in <module>
foo.append(state)
AttributeError: ('print(foo) failed: None', "Appending 'bar' failed", "'NoneType' object has no attribute 'append'")
단순한 예쁜 프린트는
print("\n".join( "-"*i+" "+j for i,j in enumerate(e.args)))
클래스 속성은 클래스 객체와 클래스 인스턴스 모두에서 액세스할 수 있으므로 클래스 속성을 세부 정보의 저장소로 사용하는 편리한 접근 방식을 사용했습니다.
class CustomError(Exception):
def __init__(self, details: Dict):
self.details = details
그러면 코드:
raise CustomError({'data': 5})
오류 발견 시:
except CustomError as e:
# Do whatever you want with the exception instance
print(e.details)
예외에 추가 정보를 추가할 때마다 자주 사용하는 코드 일부를 제공합니다.저는 Python 2.7과 3.6 모두에서 일하고 있습니다.
import sys
import traceback
try:
a = 1
b = 1j
# The line below raises an exception because
# we cannot compare int to complex.
m = max(a, b)
except Exception as ex:
# I create my informational message for debugging:
msg = "a=%r, b=%r" % (a, b)
# Gather the information from the original exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
# Format the original exception for a nice printout:
traceback_string = ''.join(traceback.format_exception(
exc_type, exc_value, exc_traceback))
# Re-raise a new exception of the same class as the original one,
# using my custom message and the original traceback:
raise type(ex)("%s\n\nORIGINAL TRACEBACK:\n\n%s\n" % (msg, traceback_string))
위의 코드는 다음과 같이 출력됩니다.
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-6-09b74752c60d> in <module>()
14 raise type(ex)(
15 "%s\n\nORIGINAL TRACEBACK:\n\n%s\n" %
---> 16 (msg, traceback_string))
TypeError: a=1, b=1j
ORIGINAL TRACEBACK:
Traceback (most recent call last):
File "<ipython-input-6-09b74752c60d>", line 7, in <module>
m = max(a, b) # Cannot compare int to complex
TypeError: no ordering relation is defined for complex numbers
이것이 질문의 예에서 조금 벗어난다는 것을 알지만, 그래도 누군가가 유용하게 써주길 바랍니다.
PEP 678에서는 예외에 대한 노트 추가가 기본적으로 지원됩니다.
try:
raise TypeError('bad type')
except Exception as e:
e.add_note('Add some information')
raise
렌더링 대상:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: bad type
Add some information
Steve Howard 솔루션을 대체할 수 있다고 생각했습니다만, 유감스럽게도 최종 예외를 포맷하는 방법을 제어할 수 없습니다(예: 다음과 같은 예외 전에 메모를 추가할 수 없습니다).'Error in fn: {original_exc}')
트레이스 백을 보다 상세하게 제어하려면 , https://github.com/google/etils 를 사용합니다.
from etils import epy
with epy.maybe_reraise('Error in fn: '):
fn()
또는 다음 중 하나를 선택합니다.
try:
fn()
except Exception as e:
epy.reraise(e, suffix='. Did you mean y ?')
대답과 , 아주 했을 때 .__str__단, 도움이 되지 않는 요소를 배제하기 위해 유형을 변경합니다.__str__★★★★★★ 。
저는 여전히 유형을 수정하지 않는 추가적인 개선점을 찾고 싶습니다.
from contextlib import contextmanager
@contextmanager
def helpful_info():
try:
yield
except Exception as e:
class CloneException(Exception): pass
CloneException.__name__ = type(e).__name__
CloneException.__module___ = type(e).__module__
helpful_message = '%s\n\nhelpful info!' % e
import sys
raise CloneException, helpful_message, sys.exc_traceback
class BadException(Exception):
def __str__(self):
return 'wat.'
with helpful_info():
raise BadException('fooooo')
원래의 트레이스 백과 타입(이름)이 보존됩니다.
Traceback (most recent call last):
File "re_raise.py", line 20, in <module>
raise BadException('fooooo')
File "/usr/lib64/python2.6/contextlib.py", line 34, in __exit__
self.gen.throw(type, value, traceback)
File "re_raise.py", line 5, in helpful_info
yield
File "re_raise.py", line 20, in <module>
raise BadException('fooooo')
__main__.BadException: wat.
helpful info!
다른 예외를 상속하는 자체 예외를 정의하고 값을 설정할 자체 생성자를 만들 수 있습니다.
예를 들어 다음과 같습니다.
class MyError(Exception):
def __init__(self, value):
self.value = value
Exception.__init__(self)
def __str__(self):
return repr(self.value)
개인 프로젝트에 사용하는 것은 다음과 같습니다(프로덕션 코드에서 이 작업을 수행하지 않을 이유가 충분합니다).
try:
#something hazardous
except Exception as e:
insightful_message = "shouldn't have done that"
amended_args = tuple([f'{e.args[0]}\n{insightful_message}', *e.args[1:]])
e.args = amended_args
raise
코드 (1)은 에러를 대행 수신하고 (2)는 에러의 복사본을 만듭니다..args속성: 인덱스에 오류 메시지가 포함된 것으로 가정되는 튜플입니다.0는 목록 이해를 사용하여 달성됩니다. (3) 에러 메시지에 줄 바꿈과 커스텀메시지를 추가합니다.(4) 추가 아이템을 추가합니다..args(5) 복사를 태플로 변환하고 (6) 마지막으로 대체한다..args수정본을 첨부합니다.
이러한 조작의 대부분은, 이러한 조작의 불변성을 회피하기 위해서입니다..args태플을 치다
콘텍스트 매니저로 사용하고 필요에 따라 예외에 추가 메시지를 추가하기 위한 구현입니다.
from typing import Optional, Type
from types import TracebackType
class _addInfoOnException():
def __init__(self, info: str = ""):
self.info = info
def __enter__(self):
return
def __exit__(self,
exc_type: Optional[Type[BaseException]],
exc_val: BaseException, # Optional, but not None if exc_type is not None
exc_tb: TracebackType): # Optional, but not None if exc_type is not None
if exc_type:
if self.info:
newMsg = f"{self.info}\n\tLow level error: "
if len(exc_val.args) == 0:
exc_val.args = (self.info, )
elif len(exc_val.args) == 1:
exc_val.args = (f"{newMsg}{exc_val.args[0]}", )
elif len(exc_val.args) > 0:
exc_val.args = (f"{newMsg}{exc_val.args[0]}", exc_val.args[1:])
raise
사용방법:
def main():
try:
raise Exception("Example exception msg")
except Exception:
traceback.print_exc()
print("\n\n")
try:
with _addInfoOnException():
raise Exception("Example exception msg, no extra info")
except Exception:
traceback.print_exc()
print("\n\n")
try:
with _addInfoOnException("Some extra info!"):
raise Exception("Example exception msg")
except Exception:
traceback.print_exc()
print("\n\n")
if __name__ == "__main__":
main()
이 문제는 다음과 같은 트레이스백으로 해결됩니다.
Traceback (most recent call last):
File "<...>\VSCodeDevWorkspace\testis.py", line 40, in main
raise Exception("Example exception msg")
Exception: Example exception msg
Traceback (most recent call last):
File "<...>\VSCodeDevWorkspace\testis.py", line 47, in main
raise Exception("Example exception msg, no extra info")
File "<...>\VSCodeDevWorkspace\testis.py", line 47, in main
raise Exception("Example exception msg, no extra info")
Exception: Example exception msg, no extra info
Traceback (most recent call last):
File "<...>\VSCodeDevWorkspace\testis.py", line 54, in main
raise Exception("Example exception msg")
File "<...>\VSCodeDevWorkspace\testis.py", line 54, in main
raise Exception("Example exception msg")
Exception: Some extra info!
Low level error: Example exception msg
내 코드에 사용:
try:
a=1
b=0
c=a/b
except:
raise Exception(f"can't divide {a} with {b}")
출력:
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_11708/1469673756.py in <module>
3 b=0
----> 4 c=a/b
5
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Exception Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_11708/1469673756.py in <module>
5
6 except Exception:
----> 7 raise Exception(f"can't divide {a} with {b}")
Exception: can't divide 1 with 0
아마도요.
except Exception as e:
raise IOError(e.message + 'happens at %s'%arg1)
언급URL : https://stackoverflow.com/questions/6062576/adding-information-to-an-exception
'source' 카테고리의 다른 글
| 동일한 테이블에서 업데이트를 수행한 다음 INSERT를 수행하기 위한 MariaDB 트리거 (0) | 2022.12.03 |
|---|---|
| jsonpath를 사용하여 멤버 수를 어떻게 계산합니까? (0) | 2022.12.03 |
| OS X의 sem_init (0) | 2022.11.24 |
| C 표준 라이브러리의 기능을 위험하게 하는 것은 무엇이며, 대체 방법은 무엇입니까? (0) | 2022.11.24 |
| Python에서 확장자가 .txt인 디렉토리에서 모든 파일 찾기 (0) | 2022.11.24 |