Package: gevent-tools
gtoolsA python library providinggeventtools:a gevent friendly pdbtree representation of running greenletsGevent friendly pdbThestandardpythonpdbmodule blocks all greenlets at the pdb prompt
(unlike a threaded app). If you want your greenlets to run in the background
you can usegtools.pdbinstead.It can be used like the standardpdb.So, imagine you have a gevent app that you want to debug:# ======# app.py# ======importgeventdefproduce(p):foriinrange(60):p.append(i)gevent.sleep(1)products=[]gevent.spawn(produce,products)to debug it just type on the console:$python-mgtools.pdbapp.pyThen hit 'n' until you reach thetask.join()line. At this point the
greenlet is already doing its work on the background. To make sure just typeproductsseveral times on the pdb console and you will see the products list
being filled by the running greenlet:>/app.py(9)<module>()->gevent.spawn(produce,products)(Pdb)products[0,1,2](Pdb)products[0,1,2,3,4,5,6,7]Usegtools.pdb.set_trace()just as you would with the standardpdb.set_trace()Monitoring greenletsgtools.tree.Tree()allows you to trace the current greenlets and display them
in a tree like structure:>>>importgevent>>>importgtools.tree>>>defiloop():...gevent.sleep(1)>>>defoloop():...gtools.spawn(iloop)...gevent.sleep(0.5)>>>task=gtools.spawn(oloop)>>># sleep just to trigger spawn of inner greenlets>>>gevent.sleep()>>>tree=gtools.tree.Tree()>>># initial status>>>print(tree)Root└─<greenlet.greenletA>status=running└─<GreenletB:oloop>status=running└─<GreenletC:iloop>status=running>>># after outer loop finishes>>>gevent.sleep(0.6)>>>print(tree)Root└─<greenlet.greenletA>status=running└─<GreenletB:oloop>status=finished:success└─<GreenletC:iloop>status=running>>># after inner loop finishes>>>gevent.sleep(0.6)>>>print(tree)Root└─<greenlet.greenletA>status=running└─<GreenletB:oloop>status=finished:success└─<GreenletC:iloop>status=dead:garbagecollected>>>deltask>>># when there are no more references to the greenlets>>>print(tree)Root└─<greenlet.greenletA>status=running└─<GreenletB:oloop>status=dead:garbagecollected└─<GreenletC:iloop>status=dead:garbagecollected>>>>>># new tree>>>print(gtools.tree.Tree())RootThe above example requires the usage ofgtools.Greenlet.To trace greenlets from an existing gevent application you simply need tomonkey-patchgevent itselfbeforeimporting your app:# ======# app.py# ======importgeventdefiloop():gevent.sleep(1)defoloop():gevent.spawn(iloop)gevent.sleep(0.5)defrun():returngevent.spawn(oloop)>>>fromgtools.monkeyimportpatch_gevent>>>patch_gevent()>>>importapp>>>importgtools.tree>>>the_app=app.run()>>># sleep just to trigger spawn of inner greenlets>>>gevent.sleep()>>>tree=gtools.tree.Tree()>>># initial status>>>print(tree)Root└─<greenlet.greenletA>status=running└─<GreenletB:oloop>status=running└─<GreenletC:iloop>status=runningIf you don't monkey patch, you can still have limited information about the
running greenlets (notice that the tree hierarchy is lost):>>>importapp>>>importgtools.tree>>>task=gevent.spawn(oloop)>>>the_app=app.run()>>># sleep just to trigger spawn of inner greenlets>>>gevent.sleep()>>>tree=gtools.tree.Tree(all=True)>>># initial status>>>print(tree)Root└─<greenlet.greenletA>status=running└─<Hub[...]>status=running├─<GreenletB:oloop>status=running└─<GreenletC:iloop>status=runningIt can even trace greenlets across multiple threads (seeexamples/tree_threads.py)