Skip to content
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

trio's excepthook competes with apport's, which is installed by default on Ubuntu #1065

Closed
mIcHyAmRaNe opened this issue May 27, 2019 · 8 comments · Fixed by #1528
Closed

Comments

@mIcHyAmRaNe
Copy link

Python version: 3.6.7
OS: Elementary OS Juno (based on ubuntu 18.04)
trio installation: pip3 install --user trio

Error: RuntimeWarning when i import trio

example:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import trio

$ ./test.py

/home/user/.local/lib/python3.6/site-packages/trio/_core/_multierror.py:450: 
RuntimeWarning: You seem to already have a custom sys.excepthook handler installed.
I'll skip installing trio's custom handler, but this means MultiErrors will not show full tracebacks.
category=RuntimeWarning
@oremanj oremanj changed the title RuntimeWarning when importing trio [trio's custom handler] trio's excepthook competes with apport's, which is installed by default on Ubuntu May 29, 2019
@oremanj
Copy link
Member

oremanj commented May 29, 2019

Yep, ubuntu by default installs a custom sys.excepthook that hooks into their system for reporting errors in ubuntu packages (apport). Trio will work fine, but like the warning says, you won't get full tracebacks on MultiErrors. I'm not sure if there's a good way around this or not... maybe we could detect a sys.excepthook named apport_excepthook and do something cleverer?

@njsmith
Copy link
Member

njsmith commented Jun 9, 2019

I guess there's no reason we couldn't detect this and do something clever. And ubuntu is kinda common :-). (But I think this hook doesn't get installed in virtualenvs, must be why we haven't had reports before?)

It looks like the code is here: https://bazaar.launchpad.net/~apport-hackers/apport/trunk/view/head:/apport_python_hook.py

So the tricky thing is that it runs, does some silent processing, and then it calls sys.__excepthook__ to actually display the message. I think for our purposes, we'd want them to do that, and then call trio_excepthook. This is tricky to monkeypatch though, because they call __excepthook__ directly by its name.

I guess we could monkeypatch sys.__excepthook__, but that feels very rude, since the whole point of __excepthook__ is to record the original pre-monkeypatching version of sys.excepthook. And it might have undesireable consequences. OTOH our hook is exactly a replacement for __excepthook__ so who knows, maybe that would work out great.

The other option I can think of is to do something wacky like:

class SysProxy:
    def __getattribute__(self, name):
        if name == "__excepthook__":
            return trio_excepthook
        else:
            return getattr(sys, name)

    def __setattr__(self, name, value):
        setattr(sys, name, value)

    def __delattr__(self, name):
        delattr(sys, name)

import apport_python_hook
apport_python_hook.sys = SysProxy()

I guess that would work fine. If there's ever any bug though then someone is going to be extremely confused trying to untangle things.

@njsmith
Copy link
Member

njsmith commented Jun 9, 2019

Also NB we can 100% reliably detect when the apport hook is installed by doing:

if sys.excepthook.__name__ == "apport_excepthook":
    import apport_python_hook
    if sys.excepthook is apport_python_hook.apport_excepthook:
        ...

@joernheissler
Copy link

Ubuntu enforces the python3-apport package upon their users if they've got xorg installed:

https://bugs.launchpad.net/bugs/1773087
https://bugs.launchpad.net/bugs/1730035

It would be nice if different except hooks could play nicely together. How about one records the previous value of sys.excepthook before installing a new hook function, and when an exception is handled, call the original hook afterwards?

def trio_excepthook(etype, value, tb):
    for chunk in traceback.format_exception(etype, value, tb):
        sys.stderr.write(chunk)
    original_excepthook(etype, value, tb)

original_excepthook = sys.excepthook
sys.excepthook = trio_excepthook

I didn't test the code, but any reason it wouldn't fix the issue?

@njsmith
Copy link
Member

njsmith commented Aug 5, 2019

@joernheissler Unfortunately, that doesn't work. The default built-in excepthook prints the exception. Trio replaces it, because Trio knows how to print exceptions better than the built-in one. If we always called the previous hook, then in a vanilla python installation we'd end up printing the exception twice. And in Ubuntu, apport's hook calls the vanilla hook, so if we call the apport hook, it all also end up printing the exception twice.

@njsmith
Copy link
Member

njsmith commented Aug 5, 2019

If this needs an urgent solution and we don't have better ideas, then one option would be to detect apport and simply disable its hook entirely. I don't think anyone actually cares about apport gathering exceptions from random user programs, and presumably no system programs are using trio anyway...

@smurfix
Copy link
Contributor

smurfix commented Aug 5, 2019

+1 on that.

@brandon-sling
Copy link

This is a bit old but I've just started running into this myself as I've deployed a package using trio on ubuntu. The idea of removing apport's hook sounds like the most appealing idea

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants