ó
è™xTc           @   sI  d  Z  d d l m Z d Z d Z d Z d Z d Z d d l Z d d l	 Z	 d d l
 Z
 d d l Z d d l Z d d l Z d	 „  Z d
 „  Z d d d „ Z d „  Z d „  Z d d d „ Z d d d d d d „ Z d d d d d d „ Z d d d d d d „ Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d S(    sŸ  
Ad-hoc tools for drawing Python object reference graphs with graphviz.

This module is more useful as a repository of sample code and ideas, than
as a finished product.  For documentation and background, read

  http://mg.pov.lt/blog/hunting-python-memleaks.html
  http://mg.pov.lt/blog/python-object-graphs.html
  http://mg.pov.lt/blog/object-graphs-with-graphviz.html

in that order.  Then use pydoc to read the docstrings, as there were
improvements made since those blog posts.

Copyright (c) 2008 Marius Gedminas <marius@pov.lt>

Released under the MIT licence.

See also:
  http://www.lshift.net/blog/2008/11/14/tracing-python-memory-leaks


Changes
=======

1.1dev (2008-09-05)
-------------------

New function: show_refs() for showing forward references.

New functions: typestats() and show_most_common_types().

Object boxes are less crammed with useless information (such as IDs).

Spawns xdot if it is available.
iÿÿÿÿ(   t   divisions"   Marius Gedminas (marius@gedmin.as)s"   Copyright (c) 2008 Marius Gedminast   MITs   1.1devs
   2008-09-05Nc            s    t  ‡  f d †  t j ƒ  Dƒ ƒ S(   sì   Count objects tracked by the garbage collector with a given class name.

    Example:

        >>> count('dict')
        42
        >>> count('MyClass')
        3

    Note that the GC does not track simple objects like int or str.
    c         3   s*   |  ]  } t  | ƒ j ˆ  k r d  Vq d S(   i   N(   t   typet   __name__(   t   .0t   o(   t   typename(    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pys	   <genexpr>R   s    (   t   sumt   gct   get_objects(   R   (    (   R   s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyt   countF   s    c          C   sS   i  }  xF t  j ƒ  D]8 } |  j t | ƒ j d ƒ |  t | ƒ j c d 7<q W|  S(   sð   Count the number of instances for each type tracked by the GC.

    Note that the GC does not track simple objects like int or str.

    Note that classes with the same name but defined in different modules
    will be lumped together.
    i    i   (   R   R	   t
   setdefaultR   R   (   t   statsR   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyt	   typestatsU   s
    i
   c         C   s£   t  t ƒ  j ƒ  d t j d ƒ d t ƒ} |  r= | |   } n  t d „  | Dƒ ƒ } | d k rk t j	 } n  x1 | |   D]% \ } } | | j
 | ƒ I| IJqv Wd S(   sã   Count the names of types with the most instances.

    Note that the GC does not track simple objects like int or str.

    Note that classes with the same name but defined in different modules
    will be lumped together.
    t   keyi   t   reversec         s   s!   |  ] \ } } t  | ƒ Vq d  S(   N(   t   len(   R   t   nameR
   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pys	   <genexpr>p   s    N(   t   sortedR   t   itemst   operatort
   itemgettert   Truet   maxt   Nonet   syst   stdoutt   ljust(   t   limitt   fR   t   widthR   R
   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyt   show_most_common_typesd   s    !	 c         C   s2   g  t  j ƒ  D]! } t | ƒ j |  k r | ^ q S(   sí   Return objects tracked by the garbage collector with a given class name.

    Example:

        >>> by_type('MyClass')
        [<mymodule.MyClass object at 0x...>]

    Note that the GC does not track simple objects like int or str.
    (   R   R	   R   R   (   R   R   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyt   by_typev   s    
c         C   s1   x* t  j ƒ  D] } t | ƒ |  k r | Sq Wd S(   së   Return an object at a given memory address.

    The reverse of id(obj):

        >>> at(id(obj)) is obj
        True

    Note that this function does not work on objects that are not tracked by
    the GC (e.g. ints or strings).
    N(   R   R	   t   idR   (   t   addrR   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyt   atƒ   s    i   c         C   sÖ  |  g } i d t  |  ƒ 6} i d t  |  ƒ 6} t | ƒ } | j t  | ƒ ƒ | j t  | ƒ ƒ | j t  | ƒ ƒ | j t  | ƒ ƒ | j t  | ƒ ƒ t j ƒ  x+| rÑ| j d ƒ } | | ƒ r| g }	 x7 | t  | ƒ d k	 r
| t  | ƒ } |	 j | ƒ qÔ W|	 S| t  | ƒ }
 |
 | k  r§ t j | ƒ } | j t  | ƒ ƒ x~ | D]s } t	 j
 | ƒ sTt  | ƒ | k r�qTn  t  | ƒ | k rT|
 d | t  | ƒ <| | t  | ƒ <| j | ƒ qTqTWq§ q§ Wd S(   s®  Find a shortest chain of references leading to obj.

    The start of the chain will be some object that matches your predicate.

    ``max_depth`` limits the search depth.

    ``extra_ignore`` can be a list of object IDs to exclude those objects from
    your search.

    Example:

        >>> find_backref_chain(obj, inspect.ismodule)
        [<module ...>, ..., obj]

    Returns None if such a chain could not be found.
    i    i   N(   R!   R   t   sett   addR   t   collectt   popt   appendt   get_referrerst   inspectt   isframe(   t   objt	   predicatet	   max_deptht   extra_ignoret   queuet   deptht   parentt   ignoret   targett   chaint   tdeptht	   referrerst   source(    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyt   find_backref_chain”   s<    	
		!i   c         C   s;   t  |  d | d | d | d | d | d t j d t ƒd S(	   sÇ  Generate an object reference graph ending at ``objs``

    The graph will show you what objects refer to ``objs``, directly and
    indirectly.

    ``objs`` can be a single object, or it can be a list of objects.

    Produces a Graphviz .dot file and spawns a viewer (xdot) if one is
    installed, otherwise converts the graph to a .png image.

    Use ``max_depth`` and ``too_many`` to limit the depth and breadth of the
    graph.

    Use ``filter`` (a predicate) and ``extra_ignore`` (a list of object IDs) to
    remove undesired objects from the graph.

    Use ``highlight`` (a predicate) to highlight certain graph nodes in blue.

    Examples:

        >>> show_backrefs(obj)
        >>> show_backrefs([obj1, obj2])
        >>> show_backrefs(obj, max_depth=5)
        >>> show_backrefs(obj, filter=lambda x: not inspect.isclass(x))
        >>> show_backrefs(obj, highlight=inspect.isclass)
        >>> show_backrefs(obj, extra_ignore=[id(locals())])

    R.   R/   t   filtert   too_manyt	   highlightt	   edge_funct   swap_source_targetN(   t
   show_graphR   R)   t   False(   t   objsR.   R/   R:   R;   R<   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyt   show_backrefsÅ   s    c         C   s;   t  |  d | d | d | d | d | d t j d t ƒd S(	   s»  Generate an object reference graph starting at ``objs``

    The graph will show you what objects are reachable from ``objs``, directly
    and indirectly.

    ``objs`` can be a single object, or it can be a list of objects.

    Produces a Graphviz .dot file and spawns a viewer (xdot) if one is
    installed, otherwise converts the graph to a .png image.

    Use ``max_depth`` and ``too_many`` to limit the depth and breadth of the
    graph.

    Use ``filter`` (a predicate) and ``extra_ignore`` (a list of object IDs) to
    remove undesired objects from the graph.

    Use ``highlight`` (a predicate) to highlight certain graph nodes in blue.

    Examples:

        >>> show_refs(obj)
        >>> show_refs([obj1, obj2])
        >>> show_refs(obj, max_depth=5)
        >>> show_refs(obj, filter=lambda x: not inspect.isclass(x))
        >>> show_refs(obj, highlight=inspect.isclass)
        >>> show_refs(obj, extra_ignore=[id(locals())])

    R.   R/   R:   R;   R<   R=   R>   N(   R?   R   t   get_referentsR   (   RA   R.   R/   R:   R;   R<   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyt	   show_refsè   s    c         C   sÁ  t  |  t t f ƒ s! |  g }  n  t d d ƒ } | d IJ| d IJg  }	 i  }
 t | ƒ } | j t |  ƒ ƒ | j t | ƒ ƒ | j t |	 ƒ ƒ | j t |
 ƒ ƒ | j t | ƒ ƒ x? |  D]7 } | d t | ƒ IJd |
 t | ƒ <|	 j | ƒ qÂ Wt	 j
 ƒ  d } xT|	 rc| d 7} |	 j d ƒ } |
 t | ƒ } | d t | ƒ t | | ƒ f IJt d d | | ƒ \ } } } t j | ƒ ržd	 } d } n  | rÍ| | ƒ rÍd
 } d
 } d | d } n  | d t | ƒ | | | f IJ| d k  r| d t | ƒ IJn  t j | ƒ s| | k r1qn  | | ƒ } | j t | ƒ ƒ d } x| D]ÿ } t j | ƒ s]t | ƒ | k rŠq]n  | r£| | ƒ r£q]n  | r¹| | } } n | | } } t | | ƒ } | d t | ƒ t | ƒ | f IJt | ƒ |
 k r.| d |
 t | ƒ <|	 j | ƒ n  | d 7} | | k r]| d t | ƒ IJPq]q]WqW| d IJ| j ƒ  d | GHt j d ƒ d k r«d GHt j d ƒ n t j d ƒ d GHd  S(   Ns   objects.dott   ws   digraph ObjectGraph {s1     node[shape=box, style=filled, fillcolor=white];s     %s[fontcolor=red];i    i   s     %s[label="%s"];g333333Ó?g333333ã?g      à?s     %s[fillcolor="%g,%g,%g"];s     %s[fontcolor=white];s     %s -> %s%s;s     %s[color=red];t   }s'   Graph written to objects.dot (%d nodes)s   which xdot >/dev/nulls   Spawning graph viewer (xdot)s   xdot objects.dot &s#   dot -Tpng objects.dot > objects.pngs   Image generated as objects.png(   i    i    i   (   i    i    g333333Ó?(   t
   isinstancet   listt   tuplet   fileR$   R%   R!   t   obj_node_idR(   R   R&   R'   t	   obj_labelt   gradientR*   t   ismoduleR+   t
   edge_labelt   closet   ost   system(   RA   R=   R>   R.   R/   R:   R;   R<   R   R0   R1   R3   R,   t   nodesR4   R6   t   ht   st   vt
   neighbourst   nR8   t   srcnodet   tgtnodet   elabel(    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyR?     s‚    


	
#	 !#


	c         C   s0   t  |  t j ƒ r d Sd t |  ƒ j d d ƒ S(   Nt   all_weakrefs_are_ones   o%dt   -t   _(   RG   t   weakreft   refR!   t   replace(   R,   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyRK   V  s    c         C   s!   t  t |  ƒ j d t |  ƒ ƒ S(   Ns   :
(   t   quoteR   R   t	   safe_repr(   R,   R1   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyRL   \  s    c         C   s(   |  j  d d ƒ j  d d ƒ j  d d ƒ S(   Ns   \s   \\s   "s   \"s   
s   \n(   Ra   (   RU   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyRb   a  s    c         C   s'   y t  |  ƒ SWn t k
 r" d SXd  S(   Ns   (unrepresentable)(   t
   short_reprt	   Exception(   R,   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyRc   e  s    c         C   s´   t  |  t t j t j t j f ƒ r+ |  j St  |  t j ƒ rg |  j d  k	 rZ |  j
 j d S|  j
 j Sn  t  |  t t t t f ƒ r� d t |  ƒ St  |  t j ƒ r¦ d St |  ƒ d  S(   Ns    (bound)s   %d itemsR\   i(   (   RG   R   t   typest
   ModuleTypet   BuiltinMethodTypet   BuiltinFunctionTypeR   t
   MethodTypet   im_selfR   t   im_funcRI   RH   t   dictR$   R   R_   R`   t   repr(   R,   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyRd   l  s    c         C   s�   | d k r |  S|  \ } } } | \ } } }	 t  | ƒ | }
 | d |
 | |
 } | d |
 | |
 } | d |
 |	 |
 } | | | f S(   Ni    i   (   t   float(   t   start_colort	   end_colorR1   R.   t   h1t   s1t   v1t   h2t   s2t   v2R   RT   RU   RV   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyRM   |  s    c         C   s¤   t  | t ƒ r+ | t |  d d  ƒ k r+ d St  |  t ƒ r  xc |  j ƒ  D]R \ } } | | k rG t  | t ƒ r‚ | r‚ d t | ƒ Sd t t | ƒ ƒ SqG qG Wn  d S(   Nt   __dict__s    [label="__dict__",weight=10]s    [label="%s",weight=2]s    [label="%s"]t    (   RG   Rm   t   getattrR   t	   iteritemst
   basestringRb   Rc   (   R8   R4   t   kRV   (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyRO   ‰  s    '(    (    (    (    (   t   __doc__t
   __future__R    t
   __author__t   __copyright__t   __license__t   __version__t   __date__R   R*   Rf   R_   R   RQ   R
   R   R   R   R    R#   R9   RB   RD   R?   RK   RL   Rb   Rc   Rd   RM   RO   (    (    (    s=   /public2/ftp/pub/ccp4/6.5/ccp4-6.5/lib/py2/libtbx/objgraph.pyt   <module>#   s>   				1"&F						