Browse Source

Merge branch 'newlodel' of git.labocleo.org:lodel2 into newlodel

prieto 7 years ago
parent
commit
a774b016c3

+ 50
- 1
lodel/editorial_model/__init__.py View File

1
-__author__ = 'roland'
1
+##@defgroup lodel2_em Editorial Model
2
+#@brief Data organisation description
3
+
4
+##@package lodel.editorial_model
5
+#@brief Editorial model package
6
+#
7
+#The editorial model defines objects with fields. This objects will be later
8
+#manipulated via @ref lodel.leapi "LeAPI"
9
+
10
+##@page lodel2_em_page Editorial Model
11
+#@ingroup lodel2_em
12
+#
13
+#@section lodel2_em_what What is an editorial model ?
14
+#
15
+#The editorial model is a kind of entity-relationship model describing
16
+#editorial objects.
17
+#
18
+#@warning The lodel.editorial_model package does not contains code executed by
19
+#instances. The editorial model is used to generate python code named 
20
+#@ref lodel2_leapi "LeAPI" and the package contains Classes that made easy
21
+#the Em manipulation
22
+#
23
+# @subsection lodel2_em_class EmClass
24
+#
25
+#An editorial object is named @ref components.EmClass "EmClass" for "Editorial
26
+# Model Class". A class is characterized by a uniq name a 
27
+#@ref lodel2_datasources "Datasource", a group, an optionnal parent EmClass and
28
+#the @ref components.EmField "EmFields" it contains.
29
+#
30
+#@par Example
31
+#<code>An "Article" is an EmClass with "article" as name, the EmClass "Text" as
32
+#parent etc...</code>
33
+#
34
+# @subsection lodel2_em_field EmField
35
+#
36
+#@ref components.EmClass "EmClasses" contains 
37
+#@ref components.EmField "EmFields". An EmField as a name (uniq in the EmClass)
38
+# and is associated to a @ref lodel2_datahandlers "DataHandler" specification.
39
+#
40
+# @subsection lodel2_em_group EmGroup
41
+#
42
+#@ref components.EmClass "EmClasses" and @ref components.EmField "EmFields"
43
+#are in @ref components.EmGroup "EmGroups". EmGroups represent a consistent
44
+#EditorialModel part that can be activated or deactivated.
45
+#
46
+#@par Example
47
+#<pre>EmGroup "authors" contains the EmClass authors and all its EmField
48
+# + "written_by" EmField (a reference field on "Author" EmClass) in the EmClass
49
+#"Text"</pre>
50
+#

+ 8
- 0
lodel/editorial_model/components.py View File

1
 #-*- coding: utf-8 -*-
1
 #-*- coding: utf-8 -*-
2
 
2
 
3
+##@package lodel.editorial_model.components
4
+#@brief Defines all @ref lodel2_em "EM" components
5
+#@ingroup lodel2_em
6
+
3
 import itertools
7
 import itertools
4
 import warnings
8
 import warnings
5
 import copy
9
 import copy
14
 ##@brief Abstract class to represent editorial model components
18
 ##@brief Abstract class to represent editorial model components
15
 # @see EmClass EmField
19
 # @see EmClass EmField
16
 # @todo forbid '.' in uid
20
 # @todo forbid '.' in uid
21
+#@ingroup lodel2_em
17
 class EmComponent(object):
22
 class EmComponent(object):
18
     
23
     
19
     ##@brief Instanciate an EmComponent
24
     ##@brief Instanciate an EmComponent
46
 
51
 
47
 
52
 
48
 ##@brief Handles editorial model objects classes
53
 ##@brief Handles editorial model objects classes
54
+#@ingroup lodel2_em
49
 class EmClass(EmComponent):
55
 class EmClass(EmComponent):
50
     
56
     
51
     ##@brief Instanciate a new EmClass
57
     ##@brief Instanciate a new EmClass
206
 
212
 
207
 
213
 
208
 ##@brief Handles editorial model classes fields
214
 ##@brief Handles editorial model classes fields
215
+#@ingroup lodel2_em
209
 class EmField(EmComponent):
216
 class EmField(EmComponent):
210
 
217
 
211
     ##@brief Instanciate a new EmField
218
     ##@brief Instanciate a new EmField
259
         ).digest(), byteorder='big')
266
         ).digest(), byteorder='big')
260
 
267
 
261
 ##@brief Handles functionnal group of EmComponents
268
 ##@brief Handles functionnal group of EmComponents
269
+#@ingroup lodel2_em
262
 class EmGroup(object):
270
 class EmGroup(object):
263
         
271
         
264
     ##@brief Create a new EmGroup
272
     ##@brief Create a new EmGroup

+ 1
- 0
lodel/editorial_model/model.py View File

13
 from lodel.editorial_model.components import EmClass, EmField, EmGroup
13
 from lodel.editorial_model.components import EmClass, EmField, EmGroup
14
 
14
 
15
 ##@brief Describe an editorial model
15
 ##@brief Describe an editorial model
16
+#@ingroup lodel2_em
16
 class EditorialModel(object):
17
 class EditorialModel(object):
17
     
18
     
18
     ##@brief Create a new editorial model
19
     ##@brief Create a new editorial model

+ 208
- 1
lodel/leapi/__init__.py View File

1
-__author__ = 'roland'
1
+##@defgroup lodel2_leapi LeAPI
2
+#@brief Lodel2 Editorial API
3
+#
4
+#Provide access to datas via objects as defined in the Editorial Model
5
+
6
+##@package lodel.leapi
7
+#@brief Lodel2 Editorial API
8
+#
9
+# Defines an API to access to objects as described by 
10
+#@ref lodel.editorial_model "Editorial Model"
11
+
12
+##@page lodel2_leapi_page LeAPI
13
+#@ingroup lodel2_leapi
14
+#
15
+# @section lodel2_leapi_base LeAPI (Lodel Editorial API)
16
+#
17
+# LeAPI is an API that provide access to datas as defined in an 
18
+#@ref lodel2_em "Editorial Model".
19
+#
20
+#@subsection lodel2_leapi_gen LeAPI dynamic code & LeFactory
21
+#
22
+#LeAPI python code is programmaticaly generated by 
23
+#@ref lodel.leapi.lefactory "LeFactory". LeFactory generates 
24
+#@ref lodel.leapi.leobject.LeObject "LeObject" child classes.
25
+#
26
+#@par Example
27
+#<pre>
28
+#
29
+#    from lodel.leapi.leobject import LeObject
30
+#    from lodel.leapi.datahandlers.base_classes import DataField
31
+#    from lodel.plugin.hooks import LodelHook
32
+#
33
+#    class Abstract_Object(LeObject):
34
+#        _abstract = True
35
+#        _fields = None
36
+#        _uid = []
37
+#        _ro_datasource = None
38
+#        _rw_datasource = None
39
+#        _datasource_name = 'default'
40
+#        _child_classes = None
41
+#
42
+#
43
+#    class User(LeObject):
44
+#        _abstract = False
45
+#        _fields = None
46
+#        _uid = ['id']
47
+#        _ro_datasource = None
48
+#        _rw_datasource = None
49
+#        _datasource_name = 'default'
50
+#        _child_classes = None
51
+#
52
+#
53
+#    class Object(Abstract_Object):
54
+#        _abstract = True
55
+#        _fields = None
56
+#        _uid = ['lodel_id']
57
+#        _ro_datasource = None
58
+#        _rw_datasource = None
59
+#        _datasource_name = 'default'
60
+#        _child_classes = None
61
+#
62
+#
63
+#    class Entry(Object):
64
+#        _abstract = True
65
+#        _fields = None
66
+#        _uid = ['lodel_id']
67
+#        _ro_datasource = None
68
+#        _rw_datasource = None
69
+#        _datasource_name = 'default'
70
+#        _child_classes = None
71
+#
72
+#
73
+#    class Entitie(Object):
74
+#        _abstract = True
75
+#        _fields = None
76
+#        _uid = ['lodel_id']
77
+#        _ro_datasource = None
78
+#        _rw_datasource = None
79
+#        _datasource_name = 'default'
80
+#        _child_classes = None
81
+#
82
+#
83
+#    class Person(Object):
84
+#        _abstract = False
85
+#        _fields = None
86
+#        _uid = ['lodel_id']
87
+#        _ro_datasource = None
88
+#        _rw_datasource = None
89
+#        _datasource_name = 'default'
90
+#        _child_classes = None
91
+#
92
+#    class Text(Entitie):
93
+#        _abstract = True
94
+#        _fields = None
95
+#        _uid = ['lodel_id']
96
+#        _ro_datasource = None
97
+#        _rw_datasource = None
98
+#        _datasource_name = 'default'
99
+#        _child_classes = None
100
+#
101
+#
102
+#    class Publication(Entitie):
103
+#        _abstract = False
104
+#        _fields = None
105
+#        _uid = ['lodel_id']
106
+#        _ro_datasource = None
107
+#        _rw_datasource = None
108
+#        _datasource_name = 'default'
109
+#        _child_classes = None
110
+#
111
+#    Abstract_Object._set__fields({})
112
+#    Abstract_Object._child_classes = (Section, Text, Object, Entry, Collection, Text_Person, Entitie, Indextheme, Person, Indexabs, Publication, Subsection,)
113
+#    User._set__fields({
114
+#            'firstname': DataField.from_name('varchar')(**{ 'internal': False }), 
115
+#            'lastname': DataField.from_name('varchar')(**{ 'internal': False }), 
116
+#            'classname': DataField.from_name('LeobjectSubclassIdentifier')(**{ 'internal': True }), 
117
+#            'login': DataField.from_name('varchar')(**{ 'internal': True, 'uniq': True }), 
118
+#            'id': DataField.from_name('uniqid')(**{ 'internal': True }), 
119
+#            'password': DataField.from_name('password')(**{ 'internal': False })})
120
+#    User._child_classes = tuple()
121
+#    Object._set__fields({
122
+#            'date_update': DataField.from_name('datetime')(**{ 'now_on_update': True, 'internal': True }), 
123
+#            'lodel_id': DataField.from_name('uniqid')(**{ 'internal': True }), 
124
+#            'help_text': DataField.from_name('text')(**{ 'internal': True }), 
125
+#            'date_create': DataField.from_name('datetime')(**{ 'internal': True, 'now_on_create': True })})
126
+#    Object._child_classes = (Section, Text, Entry, Collection, Text_Person, Entitie, Indextheme, Person, Indexabs, Publication, Subsection,)
127
+#    Entry._set__fields({
128
+#            'date_update': DataField.from_name('datetime')(**{ 'now_on_update': True, 'internal': True }), 
129
+#            'lodel_id': DataField.from_name('uniqid')(**{ 'internal': True }), 
130
+#            'help_text': DataField.from_name('text')(**{ 'internal': True }), 
131
+#            'date_create': DataField.from_name('datetime')(**{ 'internal': True, 'now_on_create': True })})
132
+#    Entry._child_classes = tuple()
133
+#    Entitie._set__fields({
134
+#            'date_update': DataField.from_name('datetime')(**{ 'now_on_update': True, 'internal': True }), 
135
+#            'lodel_id': DataField.from_name('uniqid')(**{ 'internal': True }), 
136
+#            'help_text': DataField.from_name('text')(**{ 'internal': True }), 
137
+#            'date_create': DataField.from_name('datetime')(**{ 'internal': True, 'now_on_create': True })})
138
+#    Entitie._child_classes = (Section, Text, Text_Person, Collection, Publication, Subsection,)
139
+#    Person._set__fields({
140
+#            'date_update': DataField.from_name('datetime')(**{ 'now_on_update': True, 'internal': True }), 
141
+#            'firstname': DataField.from_name('varchar')(**{  }), 
142
+#            'lodel_id': DataField.from_name('uniqid')(**{ 'internal': True }), 
143
+#            'linked_texts': DataField.from_name('list')(**{ 'nullable': True, 'default': None, 'allowed_classes': [Text], 'back_reference': (Text, 'linked_persons') }), 
144
+#            'help_text': DataField.from_name('text')(**{ 'internal': True }), 
145
+#            'lastname': DataField.from_name('varchar')(**{  }), 
146
+#            'fullname': DataField.from_name('Concat')(**{ 'field_list': ['firstname', 'lastname'], 'immutable': True }), 
147
+#            'classname': DataField.from_name('LeobjectSubclassIdentifier')(**{ 'internal': True }), 
148
+#            'alias': DataField.from_name('set')(**{ 'nullable': True, 'default': None, 'allowed_classes': [Person] }), 
149
+#            'date_create': DataField.from_name('datetime')(**{ 'internal': True, 'now_on_create': True })})
150
+#    Person._child_classes = tuple()
151
+#    Text._set__fields({
152
+#            'date_update': DataField.from_name('datetime')(**{ 'now_on_update': True, 'internal': True }), 
153
+#            'subtitle': DataField.from_name('varchar')(**{ 'nullable': True, 'default': None }), 
154
+#            'lodel_id': DataField.from_name('uniqid')(**{ 'internal': True }), 
155
+#            'help_text': DataField.from_name('text')(**{ 'internal': True }), 
156
+#            'linked_persons': DataField.from_name('list')(**{ 'nullable': True, 'default': None, 'allowed_classes': [Person], 'back_reference': (Person, 'linked_texts') }), 
157
+#            'indexes': DataField.from_name('list')(**{ 'nullable': True, 'default': None, 'allowed_classes': [Indexabs], 'back_reference': (Indexabs, 'texts') }), 
158
+#            'title': DataField.from_name('varchar')(**{ 'nullable': True }), 
159
+#            'date_create': DataField.from_name('datetime')(**{ 'internal': True, 'now_on_create': True })})
160
+#    Text._child_classes = (Section, Subsection,)
161
+#    Publication._set__fields({
162
+#            'date_update': DataField.from_name('datetime')(**{ 'now_on_update': True, 'internal': True }), 
163
+#            'classname': DataField.from_name('LeobjectSubclassIdentifier')(**{ 'internal': True }), 
164
+#            'lodel_id': DataField.from_name('uniqid')(**{ 'internal': True }), 
165
+#            'collection': DataField.from_name('link')(**{ 'back_reference': (Collection, 'publications') }), 
166
+#            'help_text': DataField.from_name('text')(**{ 'internal': True }), 
167
+#            'date_create': DataField.from_name('datetime')(**{ 'internal': True, 'now_on_create': True })})
168
+#    Publication._child_classes = tuple()
169
+#
170
+#    #List of dynamically generated classes
171
+#    dynclasses = [Abstract_Object, User, Object, Entry, Entitie, Person, Indexabs, Text, Publication, Collection, Indextheme, Text_Person, Section, Subsection]
172
+#    #Dict of dynamically generated classes indexed by name
173
+#    dynclasses_dict = {'Abstract_Object': Abstract_Object, 'User': User, 'Object': Object, 'Entry': Entry, 'Entitie': Entitie, 'Person': Person, 'Indexabs': Indexabs, 'Text': Text, 'Publication': Publication, 'Collection': Collection, 'Indextheme': Indextheme, 'Text_Person': Text_Person, 'Section': Section, 'Subsection': Subsection}
174
+#
175
+#
176
+#    ##@brief Return a dynamically generated class given it's name
177
+#    #@param name str : The dynamic class name
178
+#    #@return False or a child class of LeObject
179
+#    def name2class(name):
180
+#        if name not in dynclasses_dict:
181
+#            return False
182
+#        return dynclasses_dict[name]
183
+#
184
+#
185
+#    ##@brief Return a dynamically generated class given it's name
186
+#    #@note Case insensitive version of name2class
187
+#    #@param name str
188
+#    #@retrun False or a child class of LeObject
189
+#    def lowername2class(name):
190
+#        name = name.lower()
191
+#        new_dict = {k.lower():v for k,v in dynclasses_dict.items()}
192
+#        if name not in new_dict:
193
+#            return False
194
+#        return new_dict[name]
195
+#
196
+#
197
+#    ##@brief Trigger dynclasses datasources initialisation
198
+#    @LodelHook("lodel2_plugins_loaded")
199
+#    def lodel2_dyncode_datasources_init(self, caller, payload):
200
+#        for cls in dynclasses:
201
+#            cls._init_datasources()
202
+#        from lodel.plugin.hooks import LodelHook
203
+#        LodelHook.call_hook("lodel2_dyncode_loaded", __name__, dynclasses)
204
+#
205
+#
206
+#
207
+#</pre>
208
+#

+ 1
- 1
lodel/leapi/leobject.py View File

116
     #   Fields datas handling methods   #
116
     #   Fields datas handling methods   #
117
     #-----------------------------------#
117
     #-----------------------------------#
118
 
118
 
119
-    ##@brief @property True if LeObject is initialized else False
119
+    ##@brief Property method True if LeObject is initialized else False
120
     @property
120
     @property
121
     def initialized(self):
121
     def initialized(self):
122
         return self.__is_initialized
122
         return self.__is_initialized

+ 0
- 1
lodel/leapi/query.py View File

454
                     msg %= (ref_class.__name__, ref_field)
454
                     msg %= (ref_class.__name__, ref_field)
455
                     logger.debug(msg)
455
                     logger.debug(msg)
456
         if len(ref_dict) == 0:
456
         if len(ref_dict) == 0:
457
-            print(ref_classes, 'DEBUG')
458
             return NameError(   "No field named '%s' in referenced objects [%s]"
457
             return NameError(   "No field named '%s' in referenced objects [%s]"
459
                                 % (ref_field,
458
                                 % (ref_field,
460
                                     ','.join([rc.__name__ for rc in ref_classes])))
459
                                     ','.join([rc.__name__ for rc in ref_classes])))

+ 91
- 38
lodel/plugin/__init__.py View File

1
 #-*- coding: utf-8 -*-
1
 #-*- coding: utf-8 -*-
2
 
2
 
3
-## @page howto_writeplugin Write a plugin howto
4
-#
5
-# @section howto_writeplugin_basicstruct Plugin basic structure
6
-# A plugins is a python package that have to contains 3 files :
7
-#- <code>__init__.py</code>
8
-#- <code>main.py</code> ( defined in @ref lodel.plugin.plugins.MAIN_FILENAME )
9
-#- <code>confspec.py</code> ( defined in
10
-#@ref lodel.plugin.plugins.CONFSPEC_FILENAME )
11
-#
12
-# There is an example plugin in @ref plugins/dummy
13
-#
14
-# @subsection howto_writreplugin_confspec Plugin configuration specification
15
-# First of all a good practice is to preffix all plugin specific configuration
16
-# key with <code>lodel2.plugin.PLUGIN_NAME</code>.
17
-#
18
-# A configuration specification is a dict containing dict containing
19
-# tupe(DEFAULT_VALUE, VALIDATOR). The first level dict keys are sections, and
20
-# the dictionnary contained in it contains conf keys. More information on 
21
-# validators : @ref lodel.settings.validator
22
-# 
23
-# @subsubsection howto_writreplugin_confspec_example Example :
24
-#
25
-#A confspec that matches this peace of configuration file
26
-#<pre>
27
-#[lodel2.plugin.fooplugin]
28
-#hello = ...
29
-#foo = ...
30
-#bar = ...
31
-#</pre>
32
-#would be
33
-#<pre>
34
-#{
35
-#   'lodel2.plugin.fooplugin': {
36
-#                                   'foo': ...,
37
-#                                   'bar': ...,
38
-#                                   'hello': ..., } }
39
-#</pre>
40
-# 
3
+##@defgroup lodel2_plugins Plugins
4
+#
5
+#Groups all stuff that concerns plugins
6
+
7
+## @page plugin_doc Lodel2 plugin documentation
8
+#@ingroup lodel2_plugins
9
+# @section plugin_doc_type Plugin types
10
+#
11
+# Plugins are organized into types. A type specify a behavior. For the moment
12
+# Lodel2 has 4 plugin types :
13
+# - **datasource** : A datasource connector plugin expose CRUD operation on a
14
+#particular datasource
15
+# - **ui** : A user interface plugin provide an interface to lodel2. For the
16
+#moment two ui are implemented
17
+#  - interactive python : the default interface, provides access to LeApi 
18
+#through interactive python interpreter
19
+#  - webui : a plugin providing a web interface to lodel2
20
+# - **session_handler** : A session handler plugin expose functions that handles
21
+#user sessions.
22
+# - **extensions** : An extension plugin can define 2 kinds of objects :
23
+#  - hooks using @ref lodel.plugin.hooks.LodelHook decorator
24
+#  - custom LeApi obect methods using @ref lodel.plugin.plugins.CustomMethod 
25
+#decorator
26
+#
27
+# @subsection Lodel2 scripts
28
+#
29
+# In instances an utility is provided : @ref install.lodel_admin . This 
30
+# utility can be runned as a CLI script 
31
+#<code>usage: lodel_admin.py [-h] [-L] [ACTION] [OPTIONS [OPTIONS ...]]</code>
32
+#
33
+# Each actions is a "lodel2 script". Thoses scripts are parts of plugins.
34
+# @ref lodel2_script "More informations on lodel2 scripting utilities"
35
+#
36
+# @section plugin_doc_struct Common plugin structure
37
+#
38
+# All plugin types has to provide mandatories information in order to be 
39
+# loaded :
40
+#
41
+# - A plugin name
42
+# - A plugin version
43
+# - A confspec indicating where to find the wanted plugin list (for example 
44
+#datasources plugins list are indicated in lodel2.datasource_connectors 
45
+#configuration key see @ref datasource_plugin.DatasourcePlugin::_plist_confspecs ). In
46
+#fact settings MUST begin by loading wanted plugin list in order to build
47
+#a "full" confspec
48
+# - A confspec indicating the plugins allowed settings (will be merged with
49
+#lodel2 confspecs)
50
+# - A loader module filename. This module is imported once settings are
51
+#fully bootstraped and loader. It triggers the module "startup".
52
+#
53
+# In order to provide this informations the develloper can use the plugin's
54
+#package <code>__init__.py</code> file. Some informations are stored in 
55
+#variables in this file. Available variables are documented in 
56
+#@ref plugin_init_specs . Here a list of basics variables :
57
+# - the plugin's name @ref plugins.PLUGIN_NAME_VARNAME
58
+# - the plugin's version @ref plugins.PLUGIN_VERSION_VARNAME
59
+# - the plugin's loader filename @ref plugins.LOADER_FILENAME_VARNAME
60
+# - the plugin's confspec filename @ref plugins.CONFSPEC_FILENAME_VARNAME (
61
+#set this variable only if you want your confspecs to be in a separated file,
62
+#else you can put the confspecs directly in a CONFSPEC variable in the
63
+#<code>__init__.py</code> file see @ref plugins.CONFSPEC_VARNAME )
64
+# - the plugin's type @ref plugins.PLUGIN_TYPE_VARNAME (if not set use 
65
+# @ref plugins.DEFAULT_PLUGIN_TYPE )
66
+# - the plugin's dependencies list @ref plugins.PLUGIN_DEPS_VARNAME
67
+#
68
+# This was the variable specification of the <code>__init__.py</code> file.
69
+#plugins can provide (in the same file) an _activate function ( 
70
+#<code>def _activate(): returns bool</code>) that return True if the plugin
71
+#is activable else False
72
+#
73
+#An example dummy plugin exists in @ref plugins.dummy
74
+#
75
+#@section plugin_doc_childclasses Plugin types implementation
76
+#
77
+# Concretely a plugin type is a child class of @ref plugins.Plugin . Plugin 
78
+# type registration is done automatically using a metaclass for 
79
+# @ref plugins.Plugin : @ref plugins.MetaPlugType . Doing this way
80
+# plugin's type list is automatically generated.
81
+#@note Plugin type handling is not fully automatic because child classes files
82
+#are not automaticaaly imported. We have to add an import instruction into 
83
+#@ref plugin file in order to trigger the registration
84
+#
85
+#The Plugin child class must set the _plist_confspecs class attribute.
86
+#
87
+#More informations :
88
+# - @ref lodel.plugin.datasource_plugin.DatasourcePlugin "DatasourcePlugin"
89
+#  - @ref lodel2_datasources "datasources"
90
+# - @ref lodel.plugin.extensions.Extension "Extensions"
91
+# - @ref lodel.plugin.interface.InterfacePlugin "InterfacePlugin"
92
+# - @ref lodel.plugin.sessionhandler.SessionHandlerPlugin "SessionHandlerPlugin"
93
+#
41
 
94
 
42
 from .hooks import LodelHook
95
 from .hooks import LodelHook
43
 from .plugins import Plugin, CustomMethod
96
 from .plugins import Plugin, CustomMethod

+ 1
- 0
lodel/plugin/core_hooks.py View File

6
 
6
 
7
 ##@package lodel.plugin.core_hooks
7
 ##@package lodel.plugin.core_hooks
8
 #@brief Lodel2 internal hooks declaration
8
 #@brief Lodel2 internal hooks declaration
9
+#@ingroup lodel2_plugins
9
 
10
 
10
 ##@brief Bootstrap hook to check datasources configuration
11
 ##@brief Bootstrap hook to check datasources configuration
11
 @LodelHook('lodel2_bootstraped')
12
 @LodelHook('lodel2_bootstraped')

+ 9
- 1
lodel/plugin/core_scripts.py View File

1
 import lodel.plugin.scripts as lodel_script
1
 import lodel.plugin.scripts as lodel_script
2
 
2
 
3
+##@package lodel.plugin.core_scripts
4
+#@brief Lodel2 internal scripts declaration
5
+#@ingroup lodel2_plugins
6
+#@ingroup lodel2_script
7
+
8
+
3
 ##@brief Implements lodel_admin.py discover-plugin action
9
 ##@brief Implements lodel_admin.py discover-plugin action
10
+#@ingroup lodel2_plugins
11
+#@ingroup lodel2_script
4
 #
12
 #
5
-#In depth directory scan to find plugins.
13
+#In depth directory scan to find plugins in order to build a plugin list.
6
 class DiscoverPlugin(lodel_script.LodelScript):
14
 class DiscoverPlugin(lodel_script.LodelScript):
7
     _action = 'discover-plugin'
15
     _action = 'discover-plugin'
8
     _description = 'Walk through given folders looking for plugins'
16
     _description = 'Walk through given folders looking for plugins'

+ 96
- 5
lodel/plugin/datasource_plugin.py View File

6
 #
6
 #
7
 #A datasource provide data access to LeAPI typically a connector on a DB
7
 #A datasource provide data access to LeAPI typically a connector on a DB
8
 #or an API
8
 #or an API
9
+#
10
+#Provide methods to initialize datasource attribute in LeAPI LeObject child
11
+#classes (see @ref leapi.leobject.LeObject._init_datasources() )
12
+#
9
 #@note For the moment implementation is done with a retro-compatibilities
13
 #@note For the moment implementation is done with a retro-compatibilities
10
 #priority and not with a convenience priority.
14
 #priority and not with a convenience priority.
11
 #@todo Refactor and rewrite lodel2 datasource handling
15
 #@todo Refactor and rewrite lodel2 datasource handling
16
+#@todo Write abstract classes for Datasource and MigrationHandler !!!
12
 class DatasourcePlugin(Plugin):
17
 class DatasourcePlugin(Plugin):
13
     
18
     
14
     ##@brief Stores confspecs indicating where DatasourcePlugin list is stored
19
     ##@brief Stores confspecs indicating where DatasourcePlugin list is stored
18
         'default': None,
23
         'default': None,
19
         'validator': SettingValidator('strip', none_is_valid = False) }
24
         'validator': SettingValidator('strip', none_is_valid = False) }
20
     _type_conf_name = 'datasource'
25
     _type_conf_name = 'datasource'
21
-    
26
+ 
27
+    ##@brief Construct a DatasourcePlugin 
28
+    #@param name str : plugin name
29
+    #@see plugins.Plugin
22
     def __init__(self, name):
30
     def __init__(self, name):
23
         super().__init__(name)
31
         super().__init__(name)
24
         self.__datasource_cls = None
32
         self.__datasource_cls = None
25
-
33
+    
34
+    ##@brief Accessor to the datasource class
35
+    #@return A python datasource class
26
     def datasource_cls(self):
36
     def datasource_cls(self):
27
         if self.__datasource_cls is None:
37
         if self.__datasource_cls is None:
28
             self.__datasource_cls = self.loader_module().Datasource
38
             self.__datasource_cls = self.loader_module().Datasource
29
         return self.__datasource_cls
39
         return self.__datasource_cls
30
-
40
+    
41
+    ##@brief Accessor to migration handler class
42
+    #@return A python migration handler class
31
     def migration_handler_cls(self):
43
     def migration_handler_cls(self):
32
         return self.loader_module().migration_handler_class()
44
         return self.loader_module().migration_handler_class()
33
 
45
 
139
     @classmethod
151
     @classmethod
140
     def get_datasource(cls, ds_plugin_name):
152
     def get_datasource(cls, ds_plugin_name):
141
         return cls.get(ds_plugin_name).datasource_cls()
153
         return cls.get(ds_plugin_name).datasource_cls()
142
-
154
+    
155
+    ##@brief Given a plugin name returns a migration handler class
156
+    #@param ds_plugin_name str : a datasource plugin name
143
     @classmethod
157
     @classmethod
144
     def get_migration_handler(cls, ds_plugin_name):
158
     def get_migration_handler(cls, ds_plugin_name):
145
         return cls.get(ds_plugin_name).migration_handler_cls()
159
         return cls.get(ds_plugin_name).migration_handler_cls()
146
- 
160
+
161
+##@page lodel2_datasources Lodel2 datasources
162
+#
163
+#@par lodel2_datasources_intro Intro
164
+# A single lodel2 website can interact with multiple datasources. This page
165
+# aims to describe configuration & organisation of datasources in lodel2.
166
+# Each object is attached to a datasource. This association is done in the
167
+# editorial model, the datasource is identified by a name.
168
+#
169
+#@par Datasources declaration
170
+# To define a datasource you have to write something like this in confs file :
171
+#<pre>
172
+#[lodel2.datasources.DATASOURCE_NAME]
173
+#identifier = DATASOURCE_FAMILY.SOURCE_NAME
174
+#</pre>
175
+# See below for DATASOURCE_FAMILY & SOURCE_NAME
176
+#
177
+#@par Datasources plugins
178
+# Each datasource family is a plugin ( 
179
+#@ref plugin_doc "More informations on plugins" ). For example mysql or a 
180
+#mongodb plugins. Here is the CONFSPEC variable templates for datasources 
181
+#plugin
182
+#<pre>
183
+#CONFSPEC = {
184
+#                'lodel2.datasource.example.*' : {
185
+#                    'conf1' : VALIDATOR_OPTS,
186
+#                    'conf2' : VALIDATOR_OPTS,
187
+#                    ...
188
+#                }
189
+#}
190
+#</pre>
191
+#MySQL example
192
+#<pre>
193
+#CONFSPEC = {
194
+#                'lodel2.datasource.mysql.*' : {
195
+#                    'host': (   'localhost',
196
+#                                SettingValidator('host')),
197
+#                    'db_name': (    'lodel',
198
+#                                    SettingValidator('string')),
199
+#                    'username': (   None,
200
+#                                    SettingValidator('string')),
201
+#                    'password': (   None,
202
+#                                    SettingValidator('string')),
203
+#                }
204
+#}
205
+#</pre>
206
+#
207
+#@par Configuration example
208
+#<pre>
209
+# [lodel2.datasources.main]
210
+# identifier = mysql.Core
211
+# [lodel2.datasources.revues_write]
212
+# identifier = mysql.Revues
213
+# [lodel2.datasources.revues_read]
214
+# identifier = mysql.Revues
215
+# [lodel2.datasources.annuaire_persons]
216
+# identifier = persons_web_api.example
217
+# ;
218
+# ; Then, in the editorial model you are able to use "main", "revues_write", 
219
+# ; etc as datasource
220
+# ;
221
+# ; Here comes the datasources declarations
222
+# [lodel2.datasource.mysql.Core]
223
+# host = db.core.labocleo.org
224
+# db_name = core
225
+# username = foo
226
+# password = bar
227
+# ;
228
+# [lodel2.datasource.mysql.Revues]
229
+# host = revues.org
230
+# db_name = RO
231
+# username = foo
232
+# password = bar
233
+# ;
234
+# [lodel2.datasource.persons_web_api.example]
235
+# host = foo.bar
236
+# username = cleo
237
+#</pre>

+ 1
- 0
lodel/plugin/hooks.py View File

27
             self._hook.__name__, self._priority)
27
             self._hook.__name__, self._priority)
28
 
28
 
29
 ##@brief Decorator designed to register hook's callbacks
29
 ##@brief Decorator designed to register hook's callbacks
30
+#@ingroup lodel2_plugins
30
 #
31
 #
31
 # @note Decorated functions are expected to take 3 arguments :
32
 # @note Decorated functions are expected to take 3 arguments :
32
 #  - hook_name : the called hook name
33
 #  - hook_name : the called hook name

+ 62
- 10
lodel/plugin/plugins.py View File

14
 from lodel.exceptions import *
14
 from lodel.exceptions import *
15
 
15
 
16
 ## @package lodel.plugins Lodel2 plugins management
16
 ## @package lodel.plugins Lodel2 plugins management
17
+#@ingroup lodel2_plugins
17
 #
18
 #
18
 # Lodel2 plugins are stored in directories
19
 # Lodel2 plugins are stored in directories
19
 # A typicall lodel2 plugin directory structure looks like :
20
 # A typicall lodel2 plugin directory structure looks like :
21
 # - main.py containing hooks registration etc
22
 # - main.py containing hooks registration etc
22
 # - confspec.py containing a configuration specification dictionary named CONFSPEC
23
 # - confspec.py containing a configuration specification dictionary named CONFSPEC
23
 
24
 
25
+##@defgroup plugin_init_specs Plugins __init__.py specifications
26
+#@ingroup lodel2_plugins
27
+#@{
28
+
24
 ##@brief The package in which we will load plugins modules
29
 ##@brief The package in which we will load plugins modules
25
 VIRTUAL_PACKAGE_NAME = 'lodel.plugins'
30
 VIRTUAL_PACKAGE_NAME = 'lodel.plugins'
26
 ##@brief The temporary package to import python sources
31
 ##@brief The temporary package to import python sources
27
 VIRTUAL_TEMP_PACKAGE_NAME = 'lodel.plugin_tmp'
32
 VIRTUAL_TEMP_PACKAGE_NAME = 'lodel.plugin_tmp'
28
 ##@brief Plugin init filename
33
 ##@brief Plugin init filename
29
 INIT_FILENAME = '__init__.py' # Loaded with settings
34
 INIT_FILENAME = '__init__.py' # Loaded with settings
35
+##@brief Name of the variable containing the plugin name
30
 PLUGIN_NAME_VARNAME = '__plugin_name__'
36
 PLUGIN_NAME_VARNAME = '__plugin_name__'
37
+##@brief Name of the variable containing the plugin type
31
 PLUGIN_TYPE_VARNAME = '__plugin_type__'
38
 PLUGIN_TYPE_VARNAME = '__plugin_type__'
39
+##@brief Name of the variable containing the plugin version
32
 PLUGIN_VERSION_VARNAME = '__version__'
40
 PLUGIN_VERSION_VARNAME = '__version__'
41
+##@brief Name of the variable containing the confpsec filename
33
 CONFSPEC_FILENAME_VARNAME = '__confspec__'
42
 CONFSPEC_FILENAME_VARNAME = '__confspec__'
43
+##@brief Name of the variable containing the confspecs
34
 CONFSPEC_VARNAME = 'CONFSPEC'
44
 CONFSPEC_VARNAME = 'CONFSPEC'
45
+##@brief Name of the variable containing the loader filename
35
 LOADER_FILENAME_VARNAME = '__loader__'
46
 LOADER_FILENAME_VARNAME = '__loader__'
47
+##@brief Name of the variable containing the plugin dependencies
36
 PLUGIN_DEPS_VARNAME = '__plugin_deps__'
48
 PLUGIN_DEPS_VARNAME = '__plugin_deps__'
49
+##@brief Name of the optionnal activate method
37
 ACTIVATE_METHOD_NAME = '_activate'
50
 ACTIVATE_METHOD_NAME = '_activate'
38
 ##@brief Discover stage cache filename
51
 ##@brief Discover stage cache filename
39
 DISCOVER_CACHE_FILENAME = '.plugin_discover_cache.json'
52
 DISCOVER_CACHE_FILENAME = '.plugin_discover_cache.json'
40
 ##@brief Default & failover value for plugins path list
53
 ##@brief Default & failover value for plugins path list
41
 DEFAULT_PLUGINS_PATH_LIST = ['./plugins']
54
 DEFAULT_PLUGINS_PATH_LIST = ['./plugins']
42
 
55
 
56
+##@brief List storing the mandatory variables expected in a plugin __init__.py
57
+#file
43
 MANDATORY_VARNAMES = [PLUGIN_NAME_VARNAME, LOADER_FILENAME_VARNAME, 
58
 MANDATORY_VARNAMES = [PLUGIN_NAME_VARNAME, LOADER_FILENAME_VARNAME, 
44
     PLUGIN_VERSION_VARNAME]
59
     PLUGIN_VERSION_VARNAME]
45
 
60
 
61
+##@brief Default plugin type
46
 DEFAULT_PLUGIN_TYPE = 'extension' #Value found in lodel/plugin/extensions.py::Extensions._type_conf_name
62
 DEFAULT_PLUGIN_TYPE = 'extension' #Value found in lodel/plugin/extensions.py::Extensions._type_conf_name
47
 
63
 
64
+## @}
65
+
48
 ##@brief Describe and handle version numbers
66
 ##@brief Describe and handle version numbers
67
+#@ingroup lodel2_plugins
68
+#
69
+#A version number can be represented by a string like MAJOR.MINOR.PATCH
70
+#or by a list [MAJOR, MINOR,PATCH ].
71
+#
72
+#The class implements basics comparison function and string repr
49
 class PluginVersion(object):
73
 class PluginVersion(object):
50
 
74
 
51
     PROPERTY_LIST = ['major', 'minor', 'revision' ]
75
     PROPERTY_LIST = ['major', 'minor', 'revision' ]
82
             for i,v in enumerate(args):
106
             for i,v in enumerate(args):
83
                 self.__version[i] = v
107
                 self.__version[i] = v
84
     
108
     
109
+    ##@brief Property to access major version number
85
     @property
110
     @property
86
     def major(self):
111
     def major(self):
87
         return self.__version[0]
112
         return self.__version[0]
88
 
113
 
114
+    ##@brief Property to access minor version number
89
     @property
115
     @property
90
     def minor(self):
116
     def minor(self):
91
         return self.__version[1]
117
         return self.__version[1]
92
 
118
 
119
+    ##@brief Property to access patch version number
93
     @property
120
     @property
94
     def revision(self):
121
     def revision(self):
95
         return self.__version[2]
122
         return self.__version[2]
147
         return {'major': self.major, 'minor': self.minor,
174
         return {'major': self.major, 'minor': self.minor,
148
             'revision': self.revision}
175
             'revision': self.revision}
149
 
176
 
150
-##@brief Plugin metaclass that allows to "catch" child class
151
-#declaration
177
+##@brief Plugin metaclass that allows to "catch" child class declaration
178
+#@ingroup lodel2_plugins
152
 #
179
 #
153
 #Automatic script registration on child class declaration
180
 #Automatic script registration on child class declaration
154
 class MetaPlugType(type):
181
 class MetaPlugType(type):
158
     #key is the _type_conf_name and value is the class
185
     #key is the _type_conf_name and value is the class
159
     _all_ptypes = dict()
186
     _all_ptypes = dict()
160
 
187
 
188
+    ##@brief type constructor reimplementation
161
     def __init__(self, name, bases, attrs):
189
     def __init__(self, name, bases, attrs):
162
         #Here we can store all child classes of Plugin
190
         #Here we can store all child classes of Plugin
163
         super().__init__(name, bases, attrs)
191
         super().__init__(name, bases, attrs)
165
             return
193
             return
166
         #Regitering a new plugin type
194
         #Regitering a new plugin type
167
         MetaPlugType._all_ptypes[self._type_conf_name] = self
195
         MetaPlugType._all_ptypes[self._type_conf_name] = self
168
-
196
+    
197
+    ##@brief Accessor to the list of plugin types
198
+    #@return A copy of _all_ptypes attribute (a dict with typename as key
199
+    #and the class as value)
169
     @classmethod
200
     @classmethod
170
     def all_types(cls):
201
     def all_types(cls):
171
         return copy.copy(cls._all_ptypes)
202
         return copy.copy(cls._all_ptypes)
172
-
203
+    
204
+    ##@brief Accessor to the list of plugin names
205
+    #@return a list of plugin name
173
     @classmethod
206
     @classmethod
174
     def all_ptype_names(cls):
207
     def all_ptype_names(cls):
175
         return list(cls._all_ptypes.keys())
208
         return list(cls._all_ptypes.keys())
176
-
209
+    
210
+    ##@brief Given a plugin type name return a Plugin child class
211
+    #@param ptype_name str : a plugin type name
212
+    #@return A Plugin child class
213
+    #@throw PluginError if ptype_name is not an exsiting plugin type name
177
     @classmethod
214
     @classmethod
178
     def type_from_name(cls, ptype_name):
215
     def type_from_name(cls, ptype_name):
179
         if ptype_name not in cls._all_ptypes:
216
         if ptype_name not in cls._all_ptypes:
181
         return cls._all_ptypes[ptype_name]
218
         return cls._all_ptypes[ptype_name]
182
 
219
 
183
 ##@brief Handle plugins
220
 ##@brief Handle plugins
221
+#@ingroup lodel2_plugins
184
 #
222
 #
185
 # An instance represent a loaded plugin. Class methods allow to load/preload
223
 # An instance represent a loaded plugin. Class methods allow to load/preload
186
 # plugins.
224
 # plugins.
225
     # @throw PluginError
263
     # @throw PluginError
226
     def __init__(self, plugin_name):
264
     def __init__(self, plugin_name):
227
         
265
         
266
+        ##@brief The plugin name
228
         self.name = plugin_name
267
         self.name = plugin_name
268
+        ##@brief The plugin package path
229
         self.path = self.plugin_path(plugin_name)
269
         self.path = self.plugin_path(plugin_name)
230
         
270
         
231
         ##@brief Stores the plugin module
271
         ##@brief Stores the plugin module
232
         self.module = None
272
         self.module = None
233
-        ##@breif Stores the plugin loader module
273
+        ##@brief Stores the plugin loader module
234
         self.__loader_module = None
274
         self.__loader_module = None
275
+        ##@brief The plugin confspecs
235
         self.__confspecs = dict()
276
         self.__confspecs = dict()
277
+        ##@brief Boolean flag telling if the plugin is loaded or not
236
         self.loaded = False
278
         self.loaded = False
237
         
279
         
238
         # Importing __init__.py infos in it
280
         # Importing __init__.py infos in it
295
             self.__type = DEFAULT_PLUGIN_TYPE
337
             self.__type = DEFAULT_PLUGIN_TYPE
296
         self.__type = str(self.__type).lower()
338
         self.__type = str(self.__type).lower()
297
         if self.__type not in MetaPlugType.all_ptype_names():
339
         if self.__type not in MetaPlugType.all_ptype_names():
298
-            print("FUCK : ", MetaPlugType.all_ptype_names())
299
             raise PluginError("Unknown plugin type '%s'" % self.__type)
340
             raise PluginError("Unknown plugin type '%s'" % self.__type)
300
         # Load plugin name from init file (just for checking)
341
         # Load plugin name from init file (just for checking)
301
         try:
342
         try:
474
     def confspecs(self):
515
     def confspecs(self):
475
         return copy.copy(self.__confspecs)
516
         return copy.copy(self.__confspecs)
476
 
517
 
518
+    ##@brief Accessor to confspec indicating where we can find the plugin list
519
+    #@note Abtract method implemented only for Plugin child classes
520
+    #This attribute indicate where we fetch the plugin list.
477
     @classmethod
521
     @classmethod
478
     def plist_confspecs(cls):
522
     def plist_confspecs(cls):
479
         if cls._plist_confspecs is None:
523
         if cls._plist_confspecs is None:
546
         if ptype not in MetaPlugType.all_ptype_names():
590
         if ptype not in MetaPlugType.all_ptype_names():
547
             raise PluginError("Unknown plugin type '%s'" % ptype)
591
             raise PluginError("Unknown plugin type '%s'" % ptype)
548
         pcls = MetaPlugType.type_from_name(ptype)
592
         pcls = MetaPlugType.type_from_name(ptype)
549
-        print("\n\n\nINSTANCIATING : ", pcls, " from name : ", ptype)
550
         plugin = pcls(plugin_name)
593
         plugin = pcls(plugin_name)
551
         cls._plugin_instances[plugin_name] = plugin
594
         cls._plugin_instances[plugin_name] = plugin
552
         logger.debug("Plugin %s available." % plugin)
595
         logger.debug("Plugin %s available." % plugin)
582
             pass
625
             pass
583
 
626
 
584
         return plist[plugin_name]['path']
627
         return plist[plugin_name]['path']
585
-        
628
+    
629
+    ##@brief Return the plugin module name
630
+    #
631
+    #This module name is the "virtual" module where we imported the plugin.
632
+    #
633
+    #Typically composed like VIRTUAL_PACKAGE_NAME.PLUGIN_NAME
634
+    #@param plugin_name str : a plugin name
635
+    #@return a string representing a module name
586
     @classmethod
636
     @classmethod
587
     def plugin_module_name(cls, plugin_name):
637
     def plugin_module_name(cls, plugin_name):
588
         return "%s.%s" % (VIRTUAL_PACKAGE_NAME, plugin_name)
638
         return "%s.%s" % (VIRTUAL_PACKAGE_NAME, plugin_name)
596
     def start(cls, plugins):
646
     def start(cls, plugins):
597
         for plugin_name in plugins:
647
         for plugin_name in plugins:
598
             cls.register(plugin_name)
648
             cls.register(plugin_name)
599
-        
649
+    
650
+    ##@brief Attempt to "restart" the Plugin class
600
     @classmethod
651
     @classmethod
601
     def clear(cls):
652
     def clear(cls):
602
         if cls._plugin_directories is not None:
653
         if cls._plugin_directories is not None:
778
 
829
 
779
 ##@brief Decorator class designed to allow plugins to add custom methods
830
 ##@brief Decorator class designed to allow plugins to add custom methods
780
 #to LeObject childs (dyncode objects)
831
 #to LeObject childs (dyncode objects)
832
+#@ingroup lodel2_plugins
781
 #
833
 #
782
 class CustomMethod(object):
834
 class CustomMethod(object):
783
     ##@brief Stores registered custom methods
835
     ##@brief Stores registered custom methods

+ 15
- 1
lodel/plugin/scripts.py View File

4
 from lodel import logger
4
 from lodel import logger
5
 from lodel.exceptions import *
5
 from lodel.exceptions import *
6
 
6
 
7
+##@defgroup lodel2_script Administration scripts
8
+#@ingroup lodel2_plugins
9
+
10
+##@package lodel.plugin.script
11
+#@brief Lodel2 utility for writting administration scripts
12
+#@ingroup lodel2_plugins
13
+#@ingroup lodel2_script
14
+
7
 ##@brief Stores registered scripts
15
 ##@brief Stores registered scripts
16
+#@todo store it in MetaLodelScript
8
 __registered_scripts = dict()
17
 __registered_scripts = dict()
9
 
18
 
10
 ##@brief LodelScript metaclass that allows to "catch" child class
19
 ##@brief LodelScript metaclass that allows to "catch" child class
11
 #declaration
20
 #declaration
21
+#@ingroup lodel2_script
22
+#@ingroup lodel2_plugins
12
 #
23
 #
13
 #Automatic script registration on child class declaration
24
 #Automatic script registration on child class declaration
14
 class MetaLodelScript(type):
25
 class MetaLodelScript(type):
48
     def __str__(self):
59
     def __str__(self):
49
         return '%s : %s' % (self._action, self._description)
60
         return '%s : %s' % (self._action, self._description)
50
 
61
 
62
+
63
+##@brief Class designed to facilitate custom script writting
64
+#@ingroup lodel2_plugins
65
+#@ingroup lodel2_script
51
 class LodelScript(object, metaclass=MetaLodelScript):
66
 class LodelScript(object, metaclass=MetaLodelScript):
52
     
67
     
53
     ##@brief A string to identify the action
68
     ##@brief A string to identify the action
146
     action = sys.argv[1].lower()
161
     action = sys.argv[1].lower()
147
     if action not in __registered_scripts:
162
     if action not in __registered_scripts:
148
         #Trying to parse argument with default parser
163
         #Trying to parse argument with default parser
149
-        print("PASSAGE")
150
         args = default_parser.parse_args()
164
         args = default_parser.parse_args()
151
         if args.list_actions:
165
         if args.list_actions:
152
             print("Available actions :")
166
             print("Available actions :")

+ 4
- 8
lodel/plugin/sessionhandler.py View File

5
 ##@brief SessionHandlerPlugin metaclass designed to implements a wrapper
5
 ##@brief SessionHandlerPlugin metaclass designed to implements a wrapper
6
 #between SessionHandlerPlugin classmethod and plugin loader functions
6
 #between SessionHandlerPlugin classmethod and plugin loader functions
7
 class SessionPluginWrapper(MetaPlugType):
7
 class SessionPluginWrapper(MetaPlugType):
8
+
8
     ##@brief Constant that stores all possible session actions
9
     ##@brief Constant that stores all possible session actions
9
     #
10
     #
10
     #Key is the SessionHandlerPlugin method name and value is SessionHandler
11
     #Key is the SessionHandlerPlugin method name and value is SessionHandler
32
         return super().__getattribute__(name)
33
         return super().__getattribute__(name)
33
 
34
 
34
 
35
 
35
-##@page lodel2_plugins Lodel2 plugins system
36
-#
37
-# @par Plugin structure
38
-#A plugin is  a package (a folder containing, at least, an __init__.py file.
39
-#This file should expose multiple things :
40
-# - a CONFSPEC variable containing configuration specifications
41
-# - an _activate() method that returns True if the plugin can be activated (
42
-# optionnal)
36
+##@brief Singleton class designed to handle session handler plugin
43
 #
37
 #
38
+#@note This class is a singleton because only one session handler can be
39
+#loaded by instance
44
 class SessionHandlerPlugin(Plugin, metaclass=SessionPluginWrapper): 
40
 class SessionHandlerPlugin(Plugin, metaclass=SessionPluginWrapper): 
45
     ##@brief Stores the singleton instance
41
     ##@brief Stores the singleton instance
46
     _instance = None
42
     _instance = None

+ 1
- 75
plugins/dummy_datasource/__init__.py View File

13
                     SettingValidator('dummy'))}
13
                     SettingValidator('dummy'))}
14
 }
14
 }
15
 
15
 
16
-##@page lodel2_datasources Lodel2 datasources
17
-#
18
-#@par lodel2_datasources_intro Intro
19
-# A single lodel2 website can interact with multiple datasources. This page
20
-# aims to describe configuration & organisation of datasources in lodel2.
21
-# Each object is attached to a datasource. This association is done in the
22
-# editorial model, the datasource is identified by a name.
23
-#
24
-#@par Datasources declaration
25
-# To define a datasource you have to write something like this in confs file :
26
-#<pre>
27
-#[lodel2.datasources.DATASOURCE_NAME]
28
-#identifier = DATASOURCE_FAMILY.SOURCE_NAME
29
-#</pre>
30
-# See below for DATASOURCE_FAMILY & SOURCE_NAME
31
-#
32
-#@par Datasources plugins
33
-# Each datasource family is a plugin. For example mysql or a mongodb plugins.
34
-# Here is the CONFSPEC variable templates for datasources plugins
35
-#<pre>
36
-#CONFSPEC = {
37
-#                'lodel2.datasource.example.*' : {
38
-#                    'conf1' : VALIDATOR_OPTS,
39
-#                    'conf2' : VALIDATOR_OPTS,
40
-#                    ...
41
-#                }
42
-#}
43
-#</pre>
44
-#MySQL example
45
-#<pre>
46
-#CONFSPEC = {
47
-#                'lodel2.datasource.mysql.*' : {
48
-#                    'host': (   'localhost',
49
-#                                SettingValidator('host')),
50
-#                    'db_name': (    'lodel',
51
-#                                    SettingValidator('string')),
52
-#                    'username': (   None,
53
-#                                    SettingValidator('string')),
54
-#                    'password': (   None,
55
-#                                    SettingValidator('string')),
56
-#                }
57
-#}
58
-#</pre>
59
-#
60
-#@par Configuration example
61
-#<pre>
62
-# [lodel2.datasources.main]
63
-# identifier = mysql.Core
64
-# [lodel2.datasources.revues_write]
65
-# identifier = mysql.Revues
66
-# [lodel2.datasources.revues_read]
67
-# identifier = mysql.Revues
68
-# [lodel2.datasources.annuaire_persons]
69
-# identifier = persons_web_api.example
70
-# ;
71
-# ; Then, in the editorial model you are able to use "main", "revues_write", 
72
-# ; etc as datasource
73
-# ;
74
-# ; Here comes the datasources declarations
75
-# [lodel2.datasource.mysql.Core]
76
-# host = db.core.labocleo.org
77
-# db_name = core
78
-# username = foo
79
-# password = bar
80
-# ;
81
-# [lodel2.datasource.mysql.Revues]
82
-# host = revues.org
83
-# db_name = RO
84
-# username = foo
85
-# password = bar
86
-# ;
87
-# [lodel2.datasource.persons_web_api.example]
88
-# host = foo.bar
89
-# username = cleo
90
-#</pre>
16
+

Loading…
Cancel
Save