B
    `>W                 @   s   d dl mZmZmZ d dlmZ d dlZd dlmZ dZ	dZ
G dd deZG d	d
 d
eZG dd deZdddZdddZG dd deZG dd deZdS )    )
getmembersgetmroisclass)iter_modulesN)getFrameInfoZ__venusian_callbacks__Z__venusian_liftonly_callbacks__c               @   s   e Zd Zdd ZdddZdS )Scannerc             K   s   | j | d S )N)__dict__update)selfkw r   Y/home/kop/projects/devel/pgwui/test_venv/lib/python3.7/site-packages/venusian/__init__.py__init__   s    zScanner.__init__Nc          
      s  |j |dk	r*t|ts"t|ds*|g}n|dkr6g }dd |D }dd |D dd |D dd |D fdd	  fd
d}x t|D ]\}}||| qW t|drt|j|j d | d}	x|	D ]\}
}}|
|}|dk	rzt|dd}|dkr|j	}y||}W n t
k
rB   | }Y nX yt| W n, tk
r|   |dk	rv|| n Y nX tj|}|dk	rx$t|dD ]\}}|||| qW W dt|drt|jdr|j  X qW dS )aO   Scan a Python package and any of its subpackages.  All
        top-level objects will be considered; those marked with
        venusian callback attributes related to ``category`` will be
        processed.

        The ``package`` argument should be a reference to a Python
        package or module object.

        The ``categories`` argument should be sequence of Venusian
        callback categories (each category usually a string) or the
        special value ``None`` which means all Venusian callback
        categories.  The default is ``None``.

        The ``onerror`` argument should either be ``None`` or a callback
        function which behaves the same way as the ``onerror`` callback
        function described in
        http://docs.python.org/library/pkgutil.html#pkgutil.walk_packages .
        By default, during a scan, Venusian will propagate all errors that
        happen during its code importing process, including
        :exc:`ImportError`.  If you use a custom ``onerror`` callback, you
        can change this behavior.
        
        Here's an example ``onerror`` callback that ignores
        :exc:`ImportError`::

            import sys
            def onerror(name):
                if not issubclass(sys.exc_info()[0], ImportError):
                    raise # reraise the last exception

        The ``name`` passed to ``onerror`` is the module or package dotted
        name that could not be imported due to an exception.

        .. versionadded:: 1.0
           the ``onerror`` callback

        The ``ignore`` argument allows you to ignore certain modules,
        packages, or global objects during a scan.  It should be a sequence
        containing strings and/or callables that will be used to match
        against the full dotted name of each object encountered during a
        scan.  The sequence can contain any of these three types of objects:

        - A string representing a full dotted name.  To name an object by
          dotted name, use a string representing the full dotted name.  For
          example, if you want to ignore the ``my.package`` package *and any
          of its subobjects or subpackages* during the scan, pass
          ``ignore=['my.package']``.

        - A string representing a relative dotted name.  To name an object
          relative to the ``package`` passed to this method, use a string
          beginning with a dot.  For example, if the ``package`` you've
          passed is imported as ``my.package``, and you pass
          ``ignore=['.mymodule']``, the ``my.package.mymodule`` mymodule *and
          any of its subobjects or subpackages* will be omitted during scan
          processing.

        - A callable that accepts a full dotted name string of an object as
          its single positional argument and returns ``True`` or ``False``.
          For example, if you want to skip all packages, modules, and global
          objects with a full dotted path that ends with the word "tests", you
          can use ``ignore=[re.compile('tests$').search]``.  If the callable
          returns ``True`` (or anything else truthy), the object is ignored,
          if it returns ``False`` (or anything else falsy) the object is not
          ignored.  *Note that unlike string matches, ignores that use a
          callable don't cause submodules and subobjects of a module or
          package represented by a dotted name to also be ignored, they match
          individual objects found during a scan, including packages,
          modules, and global objects*.

        You can mix and match the three types of strings in the list.  For
        example, if the package being scanned is ``my``,
        ``ignore=['my.package', '.someothermodule',
        re.compile('tests$').search]`` would cause ``my.package`` (and all
        its submodules and subobjects) to be ignored, ``my.someothermodule``
        to be ignored, and any modules, packages, or global objects found
        during the scan that have a full dotted name that ends with the word
        ``tests`` to be ignored.

        Note that packages and modules matched by any ignore in the list will
        not be imported, and their top-level code will not be run as a result.

        A string or callable alone can also be passed as ``ignore`` without a
        surrounding list.
        
        .. versionadded:: 1.0a3
           the ``ignore`` argument
        N__iter__c             S   s   g | ]}t |tr|qS r   )
isinstancestr).0ignr   r   r   
<listcomp>r   s    z Scanner.scan.<locals>.<listcomp>c             S   s   g | ]}| d r|qS ).)
startswith)r   r   r   r   r   r   t   s    c             S   s   g | ]}| d s|qS )r   )r   )r   r   r   r   r   r   v   s    c             S   s   g | ]}t |r|qS r   )callable)r   r   r   r   r   r   x   s    c                sZ   xD ]}|  | rdS qW x D ]}|  |r&dS q&W xD ]}|| rBdS qBW dS )NTF)r   )fullnamer   )abs_ignorescallable_ignorespkg_namerel_ignoresr   r   _ignorez   s    



zScanner.scan.<locals>._ignorec          	      s   | d | } |rd S }y t |t}|| ||s:d S W n
   d S |d kr~t| }y|  W n tk
r|   d S X x`|D ]X}||g }y0x*|D ]"\}}	}
}|	| krq||| qW W q tk
r   wY qX qW d S )Nr   )	getattrATTACH_ATTRattached_tolistkeyssort	TypeErrorget
ValueError)mod_namenameobr   Zcategory_keysattached_categoriescategory	callbackscallbackZcb_mod_nameliftidscope)r   
categoriesr
   r   r   invoke   s2    

zScanner.scan.<locals>.invoke__path__r   )onerrorignoreget_filenamefileclose)__name__r   r   hasattrr   walk_packagesr2   find_moduler   Z_get_filenamer$   
__import__	Exceptionsysmodulesr%   r6   r7   )r
   packager0   r3   r4   Zstr_ignoresr1   r(   r)   resultsimportermodnameispkgloaderr5   fnmoduler   )r   r   r   r0   r   r   r
   r   scan   sX    Y7




zScanner.scan)NNN)r8   
__module____qualname__r   rH   r   r   r   r   r      s   r   c               @   s   e Zd ZdZdd ZdS )
AttachInfoa  
    An instance of this class is returned by the
    :func:`venusian.attach` function.  It has the following
    attributes:

    ``scope``

      One of ``exec``, ``module``, ``class``, ``function call`` or
      ``unknown`` (each a string).  This is the scope detected while
      executing the decorator which runs the attach function.

    ``module``

      The module in which the decorated function was defined.

    ``locals``

      A dictionary containing decorator frame's f_locals.

    ``globals``

      A dictionary containing decorator frame's f_globals.

    ``category``

      The ``category`` argument passed to ``attach`` (or ``None``, the
      default).

    ``codeinfo``

      A tuple in the form ``(filename, lineno, function, sourceline)``
      representing the context of the venusian decorator used.  Eg.
      ``('/home/chrism/projects/venusian/tests/test_advice.py', 81,
      'testCallInfo', 'add_handler(foo, bar)')``
      
    c             K   s   | j | d S )N)r   r	   )r
   r   r   r   r   r     s    zAttachInfo.__init__N)r8   rI   rJ   __doc__r   r   r   r   r   rK      s   $rK   c                   s$   e Zd Z fddZdd Z  ZS )
Categoriesc                s4   t t|   t|tr || _n
t|| _d| _d S )NF)superdictr   r   tupleattached_ididlifted)r
   r    )	__class__r   r   r     s
    

zCategories.__init__c             C   s(   t | jtr| jt|kS | j||fkS )N)r   rQ   intrR   )r
   r'   r(   objr   r   r   r       s    zCategories.attached_to)r8   rI   rJ   r   r    __classcell__r   r   )rT   r   rM     s   rM      c             C   s   t |d }t|\}}}}	}
t|dd}t| dd}|
d }d||f }|dkr|td}|dksv|||dst||f}||t< ||g }nBt| td}|dks|||| st| }t	| t| ||g }|
||||f t||||	||
dS )a   Attach a callback to the wrapped object.  It will be found
    later during a scan.  This function returns an instance of the
    :class:`venusian.AttachInfo` class.

    ``category`` should be ``None`` or a string representing a decorator
    category name.

    ``name`` should be ``None`` or a string representing a subcategory within
    the category.  This will be used by the ``lift`` class decorator to
    determine if decorations of a method should be inherited or overridden.
    rX   r8   N   z%s %sclass)r/   rG   localsglobalsr+   codeinfo)r>   	_getframer   r   r%   r   r    rM   
setdefaultsetattrappendrK   )wrappedr-   r+   depthr(   framer/   rG   f_locals	f_globalsr]   module_nameZwrapped_name
class_namer.   r0   r,   r   r   r   attach&  s6    

ri    c          	   #   s   i fdd xt | |D ]\}}}|dk	r4||r4q|ryt| W n( tk
rl   |dk	rf|| n Y qX |||fV  ttj| ddpg }  fdd| D } x.t| |d ||D ]
}|V  qW q|||fV  qW dS )a  Yields (module_loader, name, ispkg) for all modules recursively
    on path, or, if path is None, all accessible modules.

    'path' should be either None or a list of paths to look for
    modules in.

    'prefix' is a string to output on the front of every module name
    on output.

    Note that this function must import all *packages* (NOT all
    modules!) on the given path, in order to access the __path__
    attribute to find submodules.

    'onerror' is a function which gets called with one argument (the name of
    the package which was being imported) if any exception occurs while
    trying to import a package.  If no onerror function is supplied, any
    exception is exceptions propagated, terminating the search.

    'ignore' is a function fed a fullly dotted name; if it returns True, the
    object is skipped and not returned in results (and if it's a package it's
    not imported).

    Examples:

    # list all modules python can access
    walk_packages()

    # list all submodules of ctypes
    walk_packages(ctypes.__path__, ctypes.__name__+'.')

    # NB: we can't just use pkgutils.walk_packages because we need to ignore
    # things
    c             S   s   | |krdS d|| < d S )NTr   )pmr   r   r   seen~  s    zwalk_packages.<locals>.seenNr2   c                s   g | ]} |s|qS r   r   )r   rk   )rm   r   r   r     s    z!walk_packages.<locals>.<listcomp>r   )r   r<   r=   r   r>   r?   r:   )pathprefixr3   r4   rB   r(   rD   itemr   )rm   r   r:   [  s"    #
r:   c               @   s"   e Zd ZdZdddZdd ZdS )lifta1  
    A class decorator which 'lifts' superclass venusian configuration
    decorations into subclasses.  For example::

      from venusian import lift
      from somepackage import venusian_decorator

      class Super(object):
          @venusian_decorator()
          def boo(self): pass

          @venusian_decorator()
          def hiss(self): pass

          @venusian_decorator()
          def jump(self): pass
              
      @lift()
      class Sub(Super):
          def boo(self): pass

          def hiss(self): pass
          
          @venusian_decorator()
          def smack(self): pass

    The above configuration will cause the callbacks of seven venusian
    decorators.  The ones attached to Super.boo, Super.hiss, and Super.jump
    *plus* ones attached to Sub.boo, Sub.hiss, Sub.hump and Sub.smack.

    If a subclass overrides a decorator on a method, its superclass decorators
    will be ignored for the subclass.  That means that in this configuration::

      from venusian import lift
      from somepackage import venusian_decorator

      class Super(object):
          @venusian_decorator()
          def boo(self): pass

          @venusian_decorator()
          def hiss(self): pass

      @lift()
      class Sub(Super):

          def boo(self): pass
          
          @venusian_decorator()
          def hiss(self): pass

    Only four, not five decorator callbacks will be run: the ones attached to
    Super.boo and Super.hiss, the inherited one of Sub.boo and the
    non-inherited one of Sub.hiss.  The inherited decorator on Super.hiss will
    be ignored for the subclass.

    The ``lift`` decorator takes a single argument named 'categories'.  If
    supplied, it should be a tuple of category names.  Only decorators
    in this category will be lifted if it is suppled.
          
    Nc             C   s
   || _ d S )N)r0   )r
   r0   r   r   r   r     s    zlift.__init__c             C   sd  t |std| td}t|\}}}}}t|dd }t|}	d|	_x t|D ]}
|
j	
td }|d kr~|
j	
td }|d k	rVx| D ]\}}|
|k	r| jr|| jkrq|	
|g }g }xf|D ]^\}}}}d}||||f}|dkrx(|D ] \}}}}|dkr||krd}qW |r|| qW t|| }||	|< qW |jrVP qVW |	r`t|t|	 |S )NzF"lift" only works as a class decorator; you tried to use it against %rrX   r8   TrZ   F)r   RuntimeErrorr>   r^   r   r   rM   rS   r   r   r%   r   LIFTONLY_ATTRitemsr0   ra   r!   r`   )r
   rb   rd   r/   rG   re   rf   r]   rg   Znewcategoriesclsr*   cnamer+   r,   Znewcallbackscb_r.   Zcscopera   ZtoappendncbZnliftidZnscopeZnewcategoryr   r   r   __call__  sH    

zlift.__call__)N)r8   rI   rJ   rL   r   rz   r   r   r   r   rq     s   =
rq   c               @   s   e Zd ZdZdd ZdS )onlyliftedfroma  
    A class decorator which marks a class as 'only lifted from'.  Decorations
    made on methods of the class won't have their callbacks called directly,
    but classes which inherit from only-lifted-from classes which also use the
    ``lift`` class decorator will use the superclass decoration callbacks.

    For example::
    
      from venusian import lift, onlyliftedfrom
      from somepackage import venusian_decorator

      @onlyliftedfrom()
      class Super(object):
          @venusian_decorator()
          def boo(self): pass

          @venusian_decorator()
          def hiss(self): pass

      @lift()
      class Sub(Super):

          def boo(self): pass
          
          def hiss(self): pass

    Only two decorator callbacks will be run: the ones attached to Sub.boo and
    Sub.hiss.  The inherited decorators on Super.boo and Super.hiss will be
    not be registered.
    c             C   sf   t |std| t|td }|j}|j}|||f}|d ksH|j| sLd S t|t t|t	| |S )NzP"onlyliftedfrom" only works as a class decorator; you tried to use it against %r)
r   rr   r   r   r8   rI   r    delattrr`   rs   )r
   rb   Zcatsrh   rg   keyr   r   r   rz   ,  s    

zonlyliftedfrom.__call__N)r8   rI   rJ   rL   rz   r   r   r   r   r{     s   r{   )NrX   N)Nrj   NN)inspectr   r   r   pkgutilr   r>   Zvenusian.advicer   r   rs   objectr   rK   rO   rM   ri   r:   rq   r{   r   r   r   r   <module>   s    c*
5
Gj