o
    k¨Êh�.  ã                   @   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-2018 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   Úabs_class_pathÚtagsÚkeywords© r   ú</var/www/html/env/lib/python3.10/site-packages/lml/plugin.pyÚ__init___   s
   
zPluginInfo.__init__c                 C   s:   |dkr| j r| j  d¡d }|S | 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u r| jV  dS | 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i |¤Ž}|  |¡ | 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   Ú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_pathr   )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 ƒ‚)zÄRaise 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 %s)r)   r/   r5   ÚkeysÚ	Exceptionr3   )r   r:   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v r:| j| D ]}|  |¡}t|ƒ}|r(||kr(q nt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/   Úlowerr5   Údynamic_load_libraryÚ_get_me_pypi_package_namer>   r?   )r   r:   Úlibraryr   Ú_PluginManager__keyrA   r	   r   r   r   r   r9     s   

zPluginManager.load_me_nowc                 C   s2   |j du r| j d|j ¡ t|jƒ}||_ |j S )z¡Dynamically 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   rD   $  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_clsrA   r   r   r   Úregister_a_plugin4  s   zPluginManager.register_a_pluginc                 C   s   |  ¡ }| j |d ¡S r   )rC   r7   r   )r   r:   rG   r   r   r   Úget_primary_keyD  s   zPluginManager.get_primary_keyc                 C   sP   d }t | ¡ ƒD ]\}}| j| ¡   |¡ |dkr| ¡ }|| j| ¡ < qd S )Nr   )Ú	enumerater   r5   rC   Úappendr7   )r   rA   Úprimary_tagÚindexr:   r   r   r   r@   H  s   üz4PluginManager._update_registry_and_expand_tag_groupsr   )r!   r   r"   r#   r   r<   r?   rB   r9   rD   rJ   rK   r@   r   r   r   r   r2   Ä   s    	
 r2   c                 C   st   t  d| j¡ | t| j< | jtv r8t| j D ]}|jr#t  d|j¡ n	t  dt|jƒ¡ |  |¡ qt| j= dS dS )z(Reigister a newly created plugin managerzdeclare '%s' plugin managerzload cached plugin info: %sN)	Úlogr/   r3   ÚPLUG_IN_MANAGERSÚCACHED_PLUGIN_INFOr   rH   r	   rB   )r	   rA   r   r   r   r8   Q  s    

þþñr8   c                 C   sF   t  | j¡}|r| || ¡ dS t dt|jƒ¡ t| j  	| ¡ dS )z*module level function to register a pluginz
caching %sN)
rQ   r   r   rJ   rP   r/   rH   r!   rR   rM   )rA   rI   Úmanagerr   r   r   r   g  s
   r   c                 C   sD   t  | j¡}|r| | ¡ dS t d| j| j¡ t| j  | ¡ dS )z- module level function to load a plugin laterzcaching %s for %sN)	rQ   r   r   rB   rP   r/   r   rR   rM   )rA   rS   r   r   r   r0   r  s   ýr0   c                 C   s8   z| j }| d¡d }| dd¡W S  ty   Y d S w )Nr   r   Ú_ú-)r   r   ÚreplaceÚAttributeError)Úmoduler   Úroot_module_namer   r   r   rE   �  s   ÿrE   c                 C   s(   z| j W S  ty   tt| ƒƒ Y S w r   )r!   rW   ÚstrÚtype)Úcls_func_or_data_typer   r   r   rH   Š  s
   ÿrH   )r#   r&   Úcollectionsr   Ú	lml.utilsr   r   rQ   r4   rR   r'   r!   rP   Úobjectr   r$   r2   r8   r   r0   rE   rH   r   r   r   r   Ú<module>   s     
d9 	