
    .~h@/                         d Z ddlZddlmZ ddlmZmZ i Z ee      Z	 ej                  e      Z G d de      Z G d de      Z G d	 d
e      Zd Zd Zd Zd Zd Zy)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                   2    e Zd ZdZ	 ddZd Zd Zd Zd Zy)	
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                 J    || _         || _        d | _        || _        || _        y N)plugin_typeabsolute_import_pathcls
properties_PluginInfo__tags)selfr
   abs_class_pathtagskeywordss        S/var/www/peopleoo.sandbox-dev.co.uk/venv/lib/python3.12/site-packages/lml/plugin.py__init__zPluginInfo.__init___   s)     '$2!"    c                     |dk(  rD| j                   r | j                   j                  d      d   }|S | j                  j                  }|S | j                  j                  |      S )Nmodule_name.r   )r   splitr   
__module__r   get)r   namer   s      r   __getattr__zPluginInfo.__getattr__h   sb    = (("77==cB1E  #hh11""4((r   c              #   l   K   | j                   | j                   y| j                   D ]  }|  yw)z
        A list of tags for identifying the plugin class

        The plugin class is described at the absolute_import_path
        N)r   r
   )r   tags     r   r   zPluginInfo.tagsq   s6      ;;"""{{ 	s   24c                     | j                   | j                  d}|j                  | j                         t	        |      S )N)r
   path)r
   r   updater   r   )r   reps     r   __repr__zPluginInfo.__repr__}   s7    ++--
 	

4??##r   c                 ,    || _         t        | |       |S r	   )r   _register_a_plugin)r   r   s     r   __call__zPluginInfo.__call__   s    4%
r   )NN)	__name__r   __qualname____doc__r   r   r   r$   r'    r   r   r   r   '   s&    5p 6:)
r   r   c                   *    e Zd ZdZd ZddZd Zd Zy)PluginInfoChainzr
    Pandas style, chained list declaration

    It is used in the plugin packages to list all plugin classes
    c                     t        j                  | j                  j                  dz   | j                  j                  z         | _        || _        y Nr   )logging	getLogger	__class__r   r(   _loggerr   )r   r!   s     r   r   zPluginInfoChain.__init__   s?    ((NN%%+dnn.E.EE
  r   Nc                 `    t        || j                  |      fi |}| j                  |       | 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_infos        r   add_a_pluginzPluginInfoChain.add_a_plugin   s;     #++I6
:B
 	""=1r   c                 ~    | j                   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)r3   debugr   r
   _load_me_later)r   plugin_info_instances     r   r6   z%PluginInfoChain.add_a_plugin_instance   s;     	# 55 ,,	

 	+,r   c                 $    | j                   d|S r/   )r   )r   r7   s     r   r5   zPluginInfoChain._get_abs_path   s    **I66r   r	   )r(   r   r)   r*   r   r9   r6   r5   r+   r   r   r-   r-      s     ((7r   r-   c                   H    e Zd ZdZd Zd Zd Zd ZddZd Z	d	 Z
d
 Zd Zy)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                     || _         t        t              | _        t	               | _        t        j                  | j                  j                  dz   | j                  j                  z         | _        t        |        y r/   )plugin_namer   listregistrydict
tag_groupsr0   r1   r2   r   r(   r3   _register_class)r   r
   s     r   r   zPluginManager.__init__   s\    &#D)&((NN%%+dnn.E.EE
 	r   c                 h    | j                   j                  d       | j                  |      } |       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)r3   r;   load_me_now)r   keyr   plugins       r   get_a_pluginzPluginManager.get_a_plugin   s.     	01!!#&xr   c                     | j                   j                  | j                  j                                t	        d| j
                  d|      )zRaise plugin not found exception

        Override this method to raise custom exception

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

        key:
            the key to find the plugin
        zNo z is found for )r3   r;   rD   keys	ExceptionrB   )r   rJ   s     r   raise_exceptionzPluginManager.raise_exception   s9     	4==--/043C3CSIJJr   c                 r    | j                   j                  d|j                         | j                  |       y)z
        Register a plugin info for later loading

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

        plugin_info:
            a instance of plugin info
        zload %s laterN)r3   r;   r   &_update_registry_and_expand_tag_groups)r   plugin_infos     r   load_me_laterzPluginManager.load_me_later   s,     	?K,L,LM33K@r   Nc                    |r| j                   j                  |       |j                         }|| j                  v r| j                  |   D ]'  }| j	                  |      }t        |      }|r||k7  r' n0 | j                   j                  d|z         | j                  |       | j                   j                  d|       |S | j                  |       y)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)r3   r;   lowerrD   dynamic_load_library_get_me_pypi_package_namerP   )r   rJ   libraryr   _PluginManager__keyrS   r   r   s           r   rI   zPluginManager.load_me_now  s     LLx(		DMM!#}}U3 
*//<7<{g5
* ""#87#BC$$S)LL5sC@J  %r   c                     |j                   D| j                  j                  d|j                  z          t	        |j                        }||_         |j                   S )zDynamically load the plugin info if not loaded


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

        a_plugin_info:
            a instance of plugin info
        zimport )r   r3   r;   r   r   )r   r8   r   s      r   rW   z"PluginManager.dynamic_load_library&  sQ     $LLy=+M+MMN!-"D"DEC #M   r   c                 ~    | j                   j                  dt        |             ||_        | j	                  |       y)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)r3   r;   _show_me_your_namer   rR   )r   
plugin_clsrS   s      r   register_a_pluginzPluginManager.register_a_plugin6  s3     	=*<Z*HI$33K@r   c                 Z    |j                         }| j                  j                  |d       S r	   )rV   rF   r   )r   rJ   rZ   s      r   get_primary_keyzPluginManager.get_primary_keyF  s$    		""5$//r   c                    d }t        |j                               D ]c  \  }}| j                  |j                            j	                  |       |dk(  r|j                         }|| j
                  |j                         <   e y )Nr   )	enumerater   rD   rV   appendrF   )r   rS   primary_tagindexrJ   s        r   rR   z4PluginManager._update_registry_and_expand_tag_groupsJ  sk    #K$4$4$67 	7JE3MM#))+&--k:z!iik+6DOOCIIK(		7r   r	   )r(   r   r)   r*   r   rL   rP   rT   rI   rW   r_   ra   rR   r+   r   r   r@   r@      s8    	 KA &D! A 07r   r@   c                    t         j                  d| j                         | t        | j                  <   | j                  t        v rt        | j                     D ]i  }|j
                  r!t         j                  d|j
                         n)t         j                  dt        |j                               | j                  |       k t        | j                  = yy)z(Reigister a newly created plugin managerzdeclare '%s' plugin managerzload cached plugin info: %sN)	logr;   rB   PLUG_IN_MANAGERSCACHED_PLUGIN_INFOr   r]   r   rT   )r   rS   s     r   rG   rG   S  s    II+S__=(+S__%
,,-coo> 	+K//		144
 		1&{7 k*	+ s/ -r   c                 `   t         j                  | j                        }|r|j                  ||        y	 t        j                  dt        |j                               t        | j                     j                  |        y# t        $ r" t        j                  dt        |             Y Mw xY w)z*module level function to register a pluginz
caching %sN)ri   r   r
   r_   rh   r;   r]   r(   AttributeErrorrj   rd   )rS   r^   managers      r   r&   r&   i  s    "";#:#:;G!!*k:	DIIl$6z7J7J$KL 	;223::;G  	DIIl$6z$BC	Ds   )B (B-,B-c                    t         j                  | j                        }|r|j                  |        yt        j                  d| j                  | j                         t        | j                     j                  |        y)z- module level function to load a plugin laterzcaching %s for %sN)	ri   r   r
   rT   rh   r;   r   rj   rd   )rS   rm   s     r   r<   r<   w  sg    "";#:#:;Gk* 			,,##	

 	;223::;Gr   c                     	 | j                   }|j                  d      d   }|j                  dd      S # t        $ r Y y w xY w)Nr   r   _-)r   r   replacerl   )moduler   root_module_names      r   rX   rX     sM    ''&,,S1!4''S11 s   14 	A A c                 b    	 | j                   S # t        $ r t        t        |             cY S w xY wr	   )r(   rl   strtype)cls_func_or_data_types    r   r]   r]     s3    0$--- 04-.//0s    ..)r*   r0   collectionsr   	lml.utilsr   r   ri   rC   rj   r1   r(   rh   objectr   r-   r@   rG   r&   r<   rX   r]   r+   r   r   <module>r|      s~   6  # 1  & g!a aH67f 67rL7F L7^0,HH0r   