-
-
Notifications
You must be signed in to change notification settings - Fork 30k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
logging.Handler.handleError regressed in python3 #78267
Comments
In python2, calling Handler.handleError may not be strictly correct, but it doesn't raise an exception. However, this has regressed since this patch: $ cat logbug.py
import logging class CustomHandler(logging.Handler):
def transmit(self, record):
return False
def emit(self, record):
if not self.transmit(record):
self.handleError(record)
def main():
logger = logging.getLogger()
logger.addHandler(CustomHandler())
logger.warning('this will work in python 2.7, but not 3')
if __name__ == '__main__':
main() $ python2 logbug.py
None
Logged from file logbug.py, line 15
$ python3 logbug.py
--- Logging error NoneType: None
Call stack:
Traceback (most recent call last):
File "logbug.py", line 20, in <module>
main()
File "logbug.py", line 15, in main
logger.warning('this will work in python 2.7, but not 3')
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/logging/__init__.py", line 1318, in warning
self._log(WARNING, msg, args, **kwargs)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/logging/__init__.py", line 1442, in _log
self.handle(record)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/logging/__init__.py", line 1452, in handle
self.callHandlers(record)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/logging/__init__.py", line 1514, in callHandlers
hdlr.handle(record)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/logging/__init__.py", line 863, in handle
self.emit(record)
File "logbug.py", line 9, in emit
self.handleError(record)
File "/usr/local/opt/python3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/logging/__init__.py", line 920, in handleError
frame = tb.tb_frame
AttributeError: 'NoneType' object has no attribute 'tb_frame' |
I realize that there is a legitimate argument that handleError() is being used wrong in the example, but since it used to work, it'd be nice if it still did. I came across this after converting a codebase to python3 and it took a while for this problem to appear. I propose the following fix: $ git diff
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 29a7d46..f2c3023 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -908,7 +908,7 @@ class Handler(Filterer):
sys.stderr.write('Call stack:\n')
# Walk the stack frame up until we're out of logging,
# so as to print the calling context.
- frame = tb.tb_frame
+ frame = tb and tb.tb_frame
while (frame and os.path.dirname(frame.f_code.co_filename) ==
__path__[0]):
frame = frame.f_back This results in: |
It seems innocuous enough, but the documentation for handleError() does say: "This method should be called from handlers when an exception is encountered during an emit() call." That documentation is the same for 2.x and 3.x. This is not how you are using it. What happens if you just raise an Exception from your transmit() method, and just call transmit() from within emit() without making a condition of the return value? |
I totally agree that this involves misusing handleError. I ended up fixing the code that originally caused the problem, since it was wrong in the first place. The reason I filed this bug and that I think it's worth fixing is that in previous versions, the problem would be that something might not get logged as expected; now the problem turns into a crash. Not only is it now a crash, but the code that crashes requires something else to go wrong (we're not calling handleError() because everything went right), which means that applications that previously tolerated something going wrong, now break. If the necessary fix was complicated, I could see the wisdom in not fixing it, but since it's simple, why not? |
For the crash to occur, it would have to be a handleError() called wrongly, when something didn't apparently go wrong (i.e. a call from outside an exception handling clause). So I'm not sure I follow your logic. I agree the change you propose is simple, but that's an orthogonal concern, IMO. |
The code that was causing this problem looked something like: --
|
I'm not sure that's evidence. That example page you linked to has 4 instances of handleError: 2 are definitions of overrides, and the other two are calls to the superclass method from those overriding methods, which would execute in an exception context if the subclass called handleError() correctly (i.e. from an exception handler). |
You're right - I misread those examples, sorry about that. It looks like my former colleague may have invented the bad code in question. I'm ok with closing as "not a bug" - I do think not fixing it adds a small potential friction for people upgrading their version of python, but maybe raising an exception is an improvement over silently doing the wrong thing? |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: