U
    [e@/                     @   s   d Z ddlZddlmZ ddlmZmZ i ZeeZ	e
eZG dd deZG dd deZG d	d
 d
eZdd Zdd Zdd Zdd Zdd ZdS )av  
    lml.plugin
    ~~~~~~~~~~~~~~~~~~~

    lml divides the plugins into two category: load-me-later plugins and
    load-me-now ones. load-me-later plugins refer to the plugins were
    loaded when needed due its bulky and/or memory hungry dependencies.
    Those plugins has to use lml and respect lml's design principle.

    load-me-now plugins refer to the plugins are immediately imported. All
    conventional Python classes are by default immediately imported.

    :class:`~lml.plugin.PluginManager` should be inherited to form new
    plugin manager class. If you have more than one plugins in your
    architecture, it is advisable to have one class per plugin type.

    :class:`~lml.plugin.PluginInfoChain` helps the plugin module to
    declare the available plugins in the module.

    :class:`~lml.plugin.PluginInfo` can be subclassed to describe
    your plugin. Its method :meth:`~lml.plugin.PluginInfo.tags`
    can be overridden to help its matching :class:`~lml.plugin.PluginManager`
    to look itself up.

    :copyright: (c) 2017-2020 by Onni Software Ltd.
    :license: New BSD License, see LICENSE for more details
    N)defaultdict)
json_dumpsdo_import_classc                   @   s:   e Zd ZdZdddZdd Zdd Zd	d
 Zdd ZdS )
PluginInfoa)  
    Information about the plugin.

    It is used together with PluginInfoChain to describe the plugins.
    Meanwhile, it is a class decorator and can be used to register a plugin
    immediately for use, in other words, the PluginInfo decorated plugin
    class is not loaded later.

    Parameters
    -------------
    name:
       plugin name

    absolute_import_path:
       absolute import path from your plugin name space for your plugin class

    tags:
       a list of keywords help the plugin manager to retrieve your plugin

    keywords:
       Another custom properties.

    Examples
    -------------

    For load-me-later plugins:

        >>> info = PluginInfo("sample",
        ...      abs_class_path='lml.plugin.PluginInfo', # demonstration only.
        ...      tags=['load-me-later'],
        ...      custom_property = 'I am a custom property')
        >>> print(info.module_name)
        lml
        >>> print(info.custom_property)
        I am a custom property

    For load-me-now plugins:

        >>> @PluginInfo("sample", tags=['load-me-now'])
        ... class TestPlugin:
        ...     def echo(self, words):
        ...         print("echoing %s" % words)

    Now let's retrive the second plugin back:

        >>> class SamplePluginManager(PluginManager):
        ...     def __init__(self):
        ...         PluginManager.__init__(self, "sample")
        >>> sample_manager = SamplePluginManager()
        >>> test_plugin=sample_manager.get_a_plugin("load-me-now")
        >>> test_plugin.echo("hey..")
        echoing hey..

    Nc                 K   s"   || _ || _d | _|| _|| _d S N)plugin_typeabsolute_import_pathcls
properties_PluginInfo__tags)selfr   Zabs_class_pathtagskeywords r   L/var/www/html/services/stratfitenv/lib/python3.8/site-packages/lml/plugin.py__init___   s
    zPluginInfo.__init__c                 C   s8   |dkr,| j r | j dd }n| jj}|S | j|S )Nmodule_name.r   )r   splitr	   
__module__r
   get)r   namer   r   r   r   __getattr__h   s    zPluginInfo.__getattr__c                 c   s*   | j dkr| jV  n| j D ]
}|V  qdS )z
        A list of tags for identifying the plugin class

        The plugin class is described at the absolute_import_path
        N)r   r   )r   tagr   r   r   r   q   s    


zPluginInfo.tagsc                 C   s"   | j | jd}|| j t|S )N)r   path)r   r   updater
   r   )r   repr   r   r   __repr__}   s
    zPluginInfo.__repr__c                 C   s   || _ t| | |S r   )r	   _register_a_plugin)r   r	   r   r   r   __call__   s    
zPluginInfo.__call__)NN)	__name__r   __qualname____doc__r   r   r   r   r   r   r   r   r   r   '   s   8   
		r   c                   @   s2   e Zd ZdZdd ZdddZdd Zd	d
 ZdS )PluginInfoChainzr
    Pandas style, chained list declaration

    It is used in the plugin packages to list all plugin classes
    c                 C   s&   t | jjd | jj | _|| _d S Nr   )logging	getLogger	__class__r   r    _loggerr   )r   r   r   r   r   r      s    zPluginInfoChain.__init__Nc                 K   s"   t || |f|}| | | S )z
        Add a plain plugin

        Parameters
        -------------

        plugin_type:
          plugin manager name

        submodule:
          the relative import path to your plugin class
        )r   _get_abs_pathadd_a_plugin_instance)r   r   	submoduler   a_plugin_infor   r   r   add_a_plugin   s     
zPluginInfoChain.add_a_pluginc                 C   s    | j d|j|j t| | S )z
        Add a plain plugin

        Parameters
        -------------

        plugin_info_instance:
          an instance of PluginInfo

        The developer has to specify the absolute import path
        zadd %s as '%s' plugin)r(   debugr   r   _load_me_later)r   Zplugin_info_instancer   r   r   r*      s    z%PluginInfoChain.add_a_plugin_instancec                 C   s   d| j |f S )Nz%s.%s)r   )r   r+   r   r   r   r)      s    zPluginInfoChain._get_abs_path)N)r    r   r!   r"   r   r-   r*   r)   r   r   r   r   r#      s
   
r#   c                   @   sZ   e Zd ZdZdd Zdd Zdd Zdd	 ZdddZdd Z	dd Z
dd Zdd Zd
S )PluginManagerz
    Load plugin info into in-memory dictionary for later import

    Parameters
    --------------

    plugin_type:
        the plugin type. All plugins of this plugin type will be
        registered to it.
    c                 C   s@   || _ tt| _t | _t| jj	d | jj
 | _t|  d S r$   )plugin_namer   listregistrydict
tag_groupsr%   r&   r'   r   r    r(   _register_class)r   r   r   r   r   r      s    
zPluginManager.__init__c                 K   s   | j d | |}| S )z Get a plugin

        Parameters
        ---------------

        key:
             the key to find the plugins

        keywords:
             additional parameters for help the retrieval of the plugins
        zget a plugin called)r(   r.   load_me_now)r   keyr   pluginr   r   r   get_a_plugin   s    
zPluginManager.get_a_pluginc                 C   s(   | j | j  td| j|f dS )zRaise plugin not found exception

        Override this method to raise custom exception

        Parameters
        -----------------

        key:
            the key to find the plugin
        zNo %s is found for %sN)r(   r.   r3   keys	Exceptionr1   )r   r8   r   r   r   raise_exception   s    zPluginManager.raise_exceptionc                 C   s   | j d|j | | dS )z
        Register a plugin info for later loading

        Parameters
        --------------

        plugin_info:
            a instance of plugin info
        zload %s laterN)r(   r.   r   &_update_registry_and_expand_tag_groups)r   plugin_infor   r   r   load_me_later   s    
zPluginManager.load_me_laterNc                 K   s   |r| j | | }|| jkr| j| D ]*}| |}t|}|rR||krRq,q, qrq,| j d|  | | | j d|| |S | | dS )z
        Import a plugin from plugin registry

        Parameters
        -----------------

        key:
            the key to find the plugin

        library:
            to use a specific plugin module
        z%s is not installedzload %s now for '%s'N)r(   r.   lowerr3   dynamic_load_library_get_me_pypi_package_namer=   )r   r8   libraryr   _PluginManager__keyr?   r	   r   r   r   r   r7     s    


zPluginManager.load_me_nowc                 C   s2   |j dkr,| jd|j  t|j}||_ |j S )zDynamically load the plugin info if not loaded


        Parameters
        --------------

        a_plugin_info:
            a instance of plugin info
        Nzimport )r	   r(   r.   r   r   )r   r,   r	   r   r   r   rB   &  s
    


z"PluginManager.dynamic_load_libraryc                 C   s&   | j dt| ||_| | dS )z for dynamically loaded plugin during runtime

        Parameters
        --------------

        plugin_cls:
            the actual plugin class refered to by the second parameter

        plugin_info:
            a instance of plugin info
        zregister %sN)r(   r.   _show_me_your_namer	   r>   )r   
plugin_clsr?   r   r   r   register_a_plugin6  s    zPluginManager.register_a_pluginc                 C   s   |  }| j|d S r   )rA   r5   r   )r   r8   rE   r   r   r   get_primary_keyF  s    zPluginManager.get_primary_keyc                 C   sP   d }t | D ]:\}}| j|  | |dkr<| }|| j| < qd S )Nr   )	enumerater   r3   rA   appendr5   )r   r?   Zprimary_tagindexr8   r   r   r   r>   J  s    z4PluginManager._update_registry_and_expand_tag_groups)N)r    r   r!   r"   r   r:   r=   r@   r7   rB   rH   rI   r>   r   r   r   r   r0      s   	
"r0   c                 C   sp   t d| j | t| j< | jtkrlt| j D ]6}|jrFt d|j nt dt|j | | q,t| j= dS )z(Reigister a newly created plugin managerzdeclare '%s' plugin managerzload cached plugin info: %sN)	logr.   r1   PLUG_IN_MANAGERSCACHED_PLUGIN_INFOr   rF   r	   r@   )r	   r?   r   r   r   r6   S  s    

r6   c                 C   sn   t | j}|r|||  nLztdt|j W n$ tk
rX   tdt| Y nX t	| j 
|  dS )z*module level function to register a pluginz
caching %sN)rN   r   r   rH   rM   r.   rF   r    AttributeErrorrO   rK   )r?   rG   managerr   r   r   r   i  s    r   c                 C   sB   t | j}|r||  n"td| j| j t| j |  dS )z- module level function to load a plugin laterzcaching %s for %sN)	rN   r   r   r@   rM   r.   r   rO   rK   )r?   rQ   r   r   r   r/   w  s    r/   c                 C   s>   z"| j }|dd }|ddW S  tk
r8   Y d S X d S )Nr   r   _-)r   r   replacerP   )moduler   Zroot_module_namer   r   r   rC     s    rC   c                 C   s.   z| j W S  tk
r(   tt|  Y S X d S r   )r    rP   strtype)Zcls_func_or_data_typer   r   r   rF     s    rF   )r"   r%   collectionsr   Z	lml.utilsr   r   rN   r2   rO   r&   r    rM   objectr   r#   r0   r6   r   r/   rC   rF   r   r   r   r   <module>   s   
d9 	