Gevent backdoor inspect runing code
<p>I am using <code>gevent</code> with its <code>Backdoor</code> feature.</p>

<p>This is a simplified version of my code :</p>

<pre><code>from gevent import backdoor, event

class App(object):
    def __init__(self):
        self.stop_event = event.Event()
        self.servers = []
        self.servers.append(backdoor.BackdoorServer((localhost, 6666))
        # There is a tcp stream server using gevent configured too

    def start(self):
        for server in self.servers:
            if not server.started:
                server.start()
        self.stop_event.wait()
        for server in self.servers:
            if server.started:
                server.stop()


def run(*args, **kw):
    app = App()
    app.start()
</code></pre>

<p>The <code>run</code> method is called in a <code>console_scripts</code> created from the <code>entry_points</code> in my <code>setup.py</code></p>

<p>I want to use my backdoor to inspect the <code>app</code> variable local in my <code>run</code> function.</p>

<p>I connect to the backdoor, and run the command <code>inspect.stack()</code>. This is what I am getting :</p>

<pre><code>[
(&lt;frame object at 0x7fa49ea0b3a0&gt;, '&lt;console&gt;', 1, '&lt;module&gt;', None, None), 
(&lt;frame object at 0x7fa49ce727f0&gt;, '/usr/lib/python2.7/code.py', 103, 'runcode', ['            exec code in self.locals\n'], 0), 
(&lt;frame object at 0x7fa49ce70250&gt;, '/usr/lib/python2.7/code.py', 87, 'runsource', ['        self.runcode(code)\n'], 0), 
(&lt;frame object at 0x7fa49ced7d38&gt;, '/usr/lib/python2.7/code.py', 265, 'push', ['        more = self.runsource(source, self.filename)\n'], 0), 
(&lt;frame object at 0x3569a40&gt;, '/usr/lib/python2.7/code.py', 243, 'interact', ['                    more = self.push(line)\n'], 0), 
(&lt;frame object at 0x7fa49ced39b0&gt;, 'path_to_project/venv/local/lib/python2.7/site-packages/gevent-1.0.2-py2.7-linux-x86_64.egg/gevent/backdoor.py', 75, '_run', ['                console.interact(banner=self.banner)\n'], 0),
(&lt;frame object at 0x7fa49ced3b90&gt;, 'path_to_project/venv/local/lib/python2.7/site-packages/gevent-1.0.2-py2.7-linux-x86_64.egg/gevent/greenlet.py', 327, 'run', ['                result = self._run(*self.args, **self.kwargs)\n'], 0)
]
</code></pre>

<p>As you can see, it seems that gevent is rewriting the stack. The <code>run</code> function from my module which is starting the program is not in it. It stops at the run method of the greenlet executing the backdoor.</p>

<p>Is there any way to access the running <code>run</code> method which has started the program in order to inspect it and access its local <code>app</code> variable ?</p>

<p>Ok, I found a solution. The <code>greenlet</code> object has a <code>parent</code> attribute to find which one has spawned the one you are currently looking at. Then the greenlet has an attribute <code>gr_frame</code> to store the stacktrace.</p>

<p>So in my case, once I am connected to the backdoor server, it would be something like that :</p>

<pre><code>&gt;&gt;&gt; import greenlet, inspect
&gt;&gt;&gt; greenlet.getcurrent()
&lt;SocketConsole at 0x7fca7122d190&gt;

&gt;&gt;&gt; greenlet.getcurrent().parent
&lt;Hub at 0x7fca71560050 epoll default pending=0 ref=4 fileno=3 resolver=&lt;gevent.resolver_thread.Resolver at 0x7fca7126a510 pool=&lt;ThreadPool at 0x7fca7127fe10 0/1/10&gt;&gt; threadpool=&lt;ThreadPool at 0x7fca7127fe10 0/1/10&gt;&gt;

&gt;&gt;&gt; greenlet.getcurrent().parent.parent
&lt;greenlet.greenlet object at 0x7fca7d9be690&gt;

&gt;&gt;&gt; inspect.getouterframes(greenlet.getcurrent().parent.parent.gr_frame)
[
...
(&lt;frame object at 0x174ac40&gt;, 'path_to_project/endpoints/app.py', 238, 'run', ['        app.start()\n'], 0),
...
]

&gt;&gt;&gt; inspect.getouterframes(greenlet.getcurrent().parent.parent.gr_frame)[4][0]
&lt;frame object at 0x174ac40&gt;

&gt;&gt;&gt; inspect.getargvalues(inspect.getouterframes(greenlet.getcurrent().parent.parent.gr_frame)[4][0]).locals 
{'args': [], 'app': &lt;endpoints.app.App object at 0x7fca71360190&gt;, 'kw': {}}

&gt;&gt;&gt; inspect.getargvalues(inspect.getouterframes(greenlet.getcurrent().parent.parent.gr_frame)[4][0]).locals['app']
&lt;endpoints.app.App object at 0x7fca71360190&gt;
</code></pre>

<p>I have noow access to the local object <code>app</code> inside the running function <code>run</code> to inspect the value of its other attributes and debug my live gevent application.</p>

python python-2.7 gevent inspect