Просмотр исходного кода

Resolves conflicts with last merge

prieto 7 лет назад
Родитель
Сommit
b79feb2ddf

+ 41
- 2
lodel/leapi/datahandlers/base_classes.py Просмотреть файл

@@ -2,7 +2,7 @@
2 2
 
3 3
 ## @package lodel.leapi.datahandlers.base_classes Define all base/abstract class for data handlers
4 4
 #
5
-# Contains custom exceptions too
5
+# Contains custom exceptions too
6 6
 
7 7
 import copy
8 8
 import importlib
@@ -14,6 +14,7 @@ from lodel.context import LodelContext
14 14
 LodelContext.expose_modules(globals(), {
15 15
     'lodel.exceptions': ['LodelException', 'LodelExceptions',
16 16
         'LodelFatalError', 'DataNoneValid', 'FieldValidationError'],
17
+    'lodel.leapi.datahandlers.exceptions': ['LodelDataHandlerConsistencyException', 'LodelDataHandlerException'],
17 18
     'lodel.logger': 'logger'})
18 19
 
19 20
 
@@ -25,7 +26,7 @@ class DataHandler(object):
25 26
     ##@brief Stores the DataHandler childs classes indexed by name
26 27
     _base_handlers = None
27 28
     ##@brief Stores custom datahandlers classes indexed by name
28
-    # @todo do it ! (like plugins, register handlers... blablabla)
29
+    # @todo do it ! (like plugins, register handlers... blablabla)
29 30
     __custom_handlers = dict()
30 31
 
31 32
     help_text = 'Generic Field Data Handler'
@@ -343,6 +344,12 @@ class Reference(DataHandler):
343 344
                     logger.warning('Object referenced does not exist')
344 345
                     return False
345 346
         return True
347
+    
348
+    ##@brief Utility method designed to fetch referenced objects
349
+    #@param value mixed : the field value
350
+    #@throw NotImplementedError
351
+    def get_referenced(self, value):
352
+        raise NotImplementedError
346 353
 
347 354
 
348 355
 ##@brief This class represent a data_handler for single reference to another object
@@ -365,6 +372,17 @@ class SingleRef(Reference):
365 372
         #    raise FieldValidationError("List or string expected for a set field")
366 373
         return value
367 374
 
375
+    ##@brief Utility method designed to fetch referenced objects
376
+    #@param value mixed : the field value
377
+    #@return A LeObject child class instance
378
+    #@throw LodelDataHandlerConsistencyException if no referenced object found
379
+    def get_referenced(self, value):
380
+        for leo_cls in self.linked_classes:
381
+            res = leo_cls.get_from_uid(value)
382
+            if res is not None:
383
+                return res
384
+        raise LodelDataHandlerConsistencyException("Unable to find \
385
+referenced object with uid %s" % value)
368 386
 
369 387
 
370 388
 ##@brief This class represent a data_handler for multiple references to another object
@@ -410,6 +428,27 @@ class MultipleRef(Reference):
410 428
             raise FieldValidationError("MultipleRef have for invalid values [%s]  :" % (",".join(error_list)))
411 429
         return new_val
412 430
 
431
+    ##@brief Utility method designed to fetch referenced objects
432
+    #@param value mixed : the field value
433
+    #@return A list of LeObject child class instance
434
+    #@throw LodelDataHandlerConsistencyException if some referenced objects
435
+    #were not found
436
+    def get_referenced(self, values):
437
+        if values is None or len(values) == 0:
438
+            return list()
439
+        left = set(values)
440
+        values = set(values)
441
+        res = list()
442
+        for leo_cls in self.linked_classes:
443
+            uidname = leo_cls.uid_fieldname()[0] #MULTIPLE UID BROKEN HERE
444
+            tmp_res = leo_cls.get(('%s in (%s)' % (uidname, ','.join(
445
+                [str(l) for l in left]))))
446
+            left ^= set(( leo.uid() for leo in tmp_res))
447
+            res += tmp_res
448
+            if len(left) == 0:
449
+                return res
450
+        raise LodelDataHandlerConsistencyException("Unable to find \
451
+some referenced objects. Followinf uid were not found : %s" % ','.join(left))
413 452
 
414 453
 ## @brief Class designed to handle datas access will fieldtypes are constructing datas
415 454
 #@ingroup lodel2_datahandlers

+ 3
- 0
lodel/leapi/datahandlers/exceptions.py Просмотреть файл

@@ -1,2 +1,5 @@
1 1
 def LodelDataHandlerException(Exception):
2 2
     pass
3
+
4
+def LodelDataHandlerConsistencyException(LodelDataHandlerException):
5
+    pass

+ 14
- 0
lodel/leapi/leobject.py Просмотреть файл

@@ -633,8 +633,22 @@ construction and consitency when datas are not complete\n")
633 633
     #@todo broken multiple UID
634 634
     @classmethod
635 635
     def get_from_uid(cls, uid):
636
+        if cls.uid_fieldname() is None:
637
+            raise LodelFatalError(
638
+                "No uid defined for class %s" % cls.__name__)
636 639
         uidname = cls.uid_fieldname()[0] #Brokes composed UID
637 640
         res = cls.get([(uidname,'=', uid)])
641
+        
642
+        #dedoublonnage vu que query ou la datasource est bugué
643
+        if len(res) > 1:
644
+            res_cp = res
645
+            res = []
646
+            while len(res_cp) > 0:
647
+                cur_res = res_cp.pop()
648
+                if cur_res.uid() in [ r.uid() for r in res_cp]:
649
+                    logger.error("DOUBLON detected in query results !!!")
650
+                else:
651
+                    res.append(cur_res)
638 652
         if len(res) > 1:
639 653
             raise LodelFatalError("Get from uid returned more than one \
640 654
 object ! For class %s with uid value = %s" % (cls, uid))

+ 28
- 0
lodel/maindoc.py Просмотреть файл

@@ -0,0 +1,28 @@
1
+#-*- coding: utf-8 -*-
2
+
3
+## @mainpage
4
+#
5
+# @section lodel_general_description General Description
6
+# Lodel is a web publishing system which is configurable to one's specific needs. It is a member of the content management systems' category.
7
+#
8
+# In its 2.0 version, it is composed from a main package, called "lodel" which contains all of its core packages and modules.
9
+#
10
+# @section lodel_core_components Core Components
11
+# The application contains the following packages in its core :
12
+#
13
+# - lodel.auth : the authentication system used to deal with the users' sessions
14
+# - lodel.editorial_model : a package containing all the tools to read/write/update an editorial model
15
+# - lodel.leapi : the main API that will be used to access the documents' data
16
+# - lodel.plugin : a plugin manager (with modules to deal with the hooks, the scripts, the options, etc ... brought in by each plugin)
17
+# - lodel.plugins : this package is used to store all the plugins that are added in Lodel
18
+# - lodel.settings : the settings management tools
19
+# - lodel.utils : several small tools that are useful and common to several core modules
20
+#
21
+# Aside from that, there are core modules :
22
+# - lodel.context : the context manager (used for the multisite functionality)
23
+# - lodel.logger : a global logging tool
24
+#
25
+# @section one_code_and_multiple_websites One code and multiple websites
26
+# Lodel can be used to manage one or many websites using the same core code. Each website will have its own activated plugins,
27
+# editorial model options and settings, all managed by the context manager.
28
+#

+ 3
- 2
lodel/plugins/dummy/main.py Просмотреть файл

@@ -2,7 +2,8 @@
2 2
 
3 3
 from lodel.context import LodelContext
4 4
 LodelContext.expose_modules(globals(), {
5
-    'lodel.plugin': ['LodelHook', 'CustomMethod']})
5
+    'lodel.plugin': ['LodelHook', 'CustomMethod'],
6
+    'lodel.settings' : 'settings'})
6 7
 
7 8
 @LodelHook('leapi_get_post')
8 9
 @LodelHook('leapi_update_pre')
@@ -12,7 +13,7 @@ LodelContext.expose_modules(globals(), {
12 13
 @LodelHook('leapi_insert_pre')
13 14
 @LodelHook('leapi_insert_post')
14 15
 def dummy_callback(hook_name, caller, payload):
15
-    if Lodel.settings.Settings.debug:
16
+    if settings.Settings.debug:
16 17
         print("\tHook %s\tcaller %s with %s" % (hook_name, caller, payload))
17 18
     return payload
18 19
 

+ 26
- 23
lodel/plugins/mongodb_datasource/datasource.py Просмотреть файл

@@ -284,13 +284,13 @@ abstract, preparing reccursiv calls" % (target, filters, relational_filters))
284 284
         return list(res.inserted_ids)
285 285
     
286 286
     ##@brief Update backref giving an action
287
-    #@param target leObject child class
288
-    #@param filters
289
-    #@param relational_filters,
290
-    #@param new_datas None | dict : optional new datas if None mean we are deleting
291
-    #@param old_datas_l None | list : if None fetch old datas from db (usefull
287
+    # @param target leObject child class
288
+    # @param filters
289
+    # @param relational_filters
290
+    # @param new_datas None | dict : optional new datas if None mean we are deleting
291
+    # @param old_datas_l None | list : if None fetch old datas from db (usefull
292 292
     #when modifications are made on instance before updating backrefs)
293
-    #@return nothing (for the moment
293
+    # @return nothing (for the moment
294 294
     def __update_backref_filtered(self, target,
295 295
             filters, relational_filters, new_datas = None, old_datas_l = None):
296 296
         #Getting all the UID of the object that will be deleted in order
@@ -309,41 +309,41 @@ abstract, preparing reccursiv calls" % (target, filters, relational_filters))
309 309
             self.__update_backref(
310 310
                 target, old_datas[uidname], old_datas, new_datas)
311 311
 
312
-    ##@brief Update back references of an object
313
-    #@ingroup plugin_mongodb_bref_op
312
+    ## @brief Update back references of an object
313
+    # @ingroup plugin_mongodb_bref_op
314 314
     #
315 315
     #old_datas and new_datas arguments are set to None to indicate 
316 316
     #insertion or deletion. Calls examples :
317
-    #@par LeObject insert __update backref call
318
-    #<pre>
317
+    # @par LeObject insert __update backref call
318
+    # <pre>
319 319
     #Insert(datas):
320 320
     #  self.make_insert(datas)
321 321
     #  self.__update_backref(self.__class__, None, datas)
322
-    #</pre>
323
-    #@par LeObject delete __update backref call
322
+    # </pre>
323
+    # @par LeObject delete __update backref call
324 324
     #Delete()
325 325
     #  old_datas = self.datas()
326 326
     #  self.make_delete()
327 327
     #  self.__update_backref(self.__class__, old_datas, None)
328
-    #@par LeObject update __update_backref call
329
-    #<pre>
328
+    # @par LeObject update __update_backref call
329
+    # <pre>
330 330
     #Update(new_datas):
331 331
     #  old_datas = self.datas()
332 332
     #  self.make_udpdate(new_datas)
333 333
     #  self.__update_backref(self.__class__, old_datas, new_datas)
334
-    #</pre>
334
+    # </pre>
335 335
     #
336
-    #@param target LeObject child classa
337
-    #@param tuid mixed : The target UID (the value that will be inserted in
336
+    # @param target LeObject child classa
337
+    # @param tuid mixed : The target UID (the value that will be inserted in
338 338
     #back references)
339
-    #@param old_datas dict : datas state before update
340
-    #@param new_datas dict : datas state after the update process
341
-    #retun None
339
+    # @param old_datas dict : datas state before update
340
+    # @param new_datas dict : datas state after the update process
341
+    # retun None
342 342
     def __update_backref(self, target, tuid, old_datas, new_datas):
343 343
         #upd_dict is the dict that will allow to run updates in an optimized
344 344
         #way (or try to help doing it)
345 345
         #
346
-        #It's struct looks like :
346
+        #Its structure looks like :
347 347
         # { LeoCLASS : {
348 348
         #       UID1: (
349 349
         #           LeoINSTANCE,
@@ -470,8 +470,7 @@ abstract, preparing reccursiv calls" % (target, filters, relational_filters))
470 470
     #@param fdh DataHandler : the source Reference DataHandler
471 471
     #@param tuid mixed : the uid of the Leo that make reference to the backref
472 472
     #@param bref_infos tuple : as returned by __bref_get_check() method
473
-    #@param old mixed : (optional **values) the old value
474
-    #@param new mixed : (optional **values) the new value
473
+    #@param values dict : contains the old and new values (optional) with the "old" and "new" keys
475 474
     #@return the new back reference field value
476 475
     def __back_ref_upd_one_value(self, fname, fdh, tuid, bref_infos, **values):
477 476
         bref_cls, bref_leo, bref_dh, bref_val = bref_infos
@@ -600,6 +599,7 @@ on non abstract childs" % act.__name__)
600 599
     #MongoDbDatasource::_connections static attribute
601 600
     #@param username str
602 601
     #@param password str
602
+    #@param db_name str : database name
603 603
     #@param ro bool : If True the Datasource is for read only, else the
604 604
     def __connect(self, username, password, db_name, ro):
605 605
         conn_string = connection_string(
@@ -763,6 +763,7 @@ on non abstract childs" % act.__name__)
763 763
     
764 764
     ##@brief Convert lodel2 filters to pymongo conditions
765 765
     #@param filters list : list of lodel filters
766
+    #@param target Datahandler : The datahandler to use to cast the value in the correct type
766 767
     #@return dict representing pymongo conditions
767 768
     @classmethod
768 769
     def __filters2mongo(cls, filters, target):
@@ -802,6 +803,7 @@ by an equality filter")
802 803
     #Convertion is done using MongoDbDatasource::lodel2mongo_op_map
803 804
     #@param op str : take value in LeFilteredQuery::_query_operators
804 805
     #@param value mixed : the value
806
+    #@param dhdl DataHandler: datahandler used to cast the values before sending them to the database
805 807
     #@return a tuple(mongo_op, mongo_value)
806 808
     @classmethod
807 809
     def __op_value_conv(cls, op, value, dhdl):
@@ -863,6 +865,7 @@ field/operator couple in a query. We will keep only the first one")
863 865
     ##@brief Correct some datas before giving them to pymongo
864 866
     #
865 867
     #For example sets has to be casted to lise
868
+    #@param cls
866 869
     #@param datas
867 870
     #@return datas
868 871
     @classmethod

+ 6
- 31
lodel/plugins/webui/templates/listing/show_object.html Просмотреть файл

@@ -1,15 +1,16 @@
1 1
 {% extends "base.html" %}
2
+{% import 'macros/show_object.html' as show_object %}
2 3
 {% import 'components/components.html' as components %}
3 4
 {% set my_class = leapi.name2class(classname) %}
4
-{% set uidfield = my_class.uid_fieldname()[0] %}
5
-{% set objects = my_class.get(('%s = %s') % (uidfield, lodel_id)) %}
6
-{% set obj = objects.pop() %}
5
+{% set obj = my_class.get_from_uid(lodel_id) %}
6
+{% if obj is none %}
7
+    ERROR <!-- conception failure, the controller should test this before calling the template -->
8
+{% endif %}
7 9
 {% if my_class.is_abstract() %}
8 10
 {% set classname = obj.data('classname') %}
9 11
 {% set my_class = my_class.name2class(classname) %}
10 12
 {% endif %}
11 13
 {% block title %}Object {{ lodel_id }} {% endblock %}
12
-{% import "components/components.html" as components %}
13 14
 {% block content %}
14 15
 <ol class="breadcrumb">
15 16
   <li><a href="/{{ root_url }}/">Home</a></li>
@@ -18,31 +19,5 @@
18 19
   <li class="active">{{ lodel_id }}</li>
19 20
 </ol>
20 21
 <h1 class="h1_lodel">Lodel 2 - {{ classname }} with uid {{ lodel_id }}</h1>
21
-<ul>
22
-    <!-- To get a component HTML code, it is necessary to call : components.<macro_name>(args) -->
23
-    {% for fieldname, fieldvalue in obj.fields(include_ro = True).items() %}
24
-        {% if fieldvalue is not none %}
25
-           {% if fieldvalue.base_type == 'ref' %}
26
-                {% if obj.data(fieldname) is iterable %}
27
-                    <li>{{ fieldname }}
28
-                    {% set l_classe = fieldvalue.allowed_classes[0] %}
29
-                        <ul>
30
-                    {% for rel in obj.data(fieldname) %}
31
-                            {% set casttype = l_classe.data_handler(l_classe.uid_fieldname()[0]).cast_type %}
32
-                            {% set rel2 = casttype(rel) %}
33
-                            <li><a href="show_object?classname={{ l_classe.__name__ }}&lodel_id={{ rel2 }}" >{{ rel2 }}</a></li>
34
-                    {% endfor %}
35
-                        </ul></li>
36
-                {% elif obj.data(fieldname) is not none %}
37
-                        {% set l_classe = fieldvalue.allowed_classes[0] %}
38
-                         {% set casttype = l_classe.data_handler(l_classe.uid_fieldname()[0]).cast_type %}
39
-                            {% set rel2 = casttype(obj.data(fieldname)) %}
40
-                            <li>{{ fieldname }} : <a href="show_object?classname={{ l_classe.__name__ }}&lodel_id={{ rel2 }}" >{{ obj.data(fieldname) }} </a></li>
41
-                {% endif %}
42
-            {% else %}
43
-                <li> {{ fieldname }} : {{ obj.data(fieldname) }} </li>
44
-            {% endif %}
45
-        {% endif %}
46
-    {% endfor %}
47
-</ul>
22
+    {{ show_object.object_ul(obj) }}
48 23
 {% endblock %}

+ 6
- 31
lodel/plugins/webui/templates/listing/show_object_detailled.html Просмотреть файл

@@ -1,7 +1,12 @@
1 1
 {% extends "base.html" %}
2
+{% import 'macros/show_object.html' as show_object %}
2 3
 {% import 'components/components.html' as components %}
3 4
 {% import "listing/display_obj.html" as edit %}
4 5
 {% set my_class = leapi.name2class(classname) %}
6
+{% set obj = my_class.get_from_uid(lodel_id) %}
7
+{% if obj is none %}
8
+    ERROR <!-- conception failure, the controller should test this before calling the template -->
9
+{% endif %}
5 10
 {% set uidfield = my_class.uid_fieldname()[0] %}
6 11
 {% set objects = my_class.get(('%s = %s') % (uidfield, lodel_id)) %}
7 12
 {% set obj = objects.pop() %}
@@ -18,35 +23,5 @@
18 23
   <li class="active">{{ lodel_id }}</li>
19 24
 </ol>
20 25
 <h1 class="h1_lodel">Lodel 2 - {{ classname }} with uid {{ lodel_id }}</h1>
21
-<ul>
22
-    <!-- To get a component HTML code, it is necessary to call : components.<macro_name>(args) -->
23
-    {% for fieldname, fieldvalue in obj.fields(include_ro = True).items() %}
24
-        {% if fieldvalue is not none %}
25
-           {% if fieldvalue.base_type == 'ref' %}
26
-                {% if obj.data(fieldname) is iterable %}
27
-                    <li>{{ fieldname }}
28
-                    {% set l_classe = fieldvalue.allowed_classes[0] %}
29
-                        <ul>
30
-                    {% set linked_objs=l_classe.get(("%s in (%s)") % (l_classe.uid_fieldname()[0], obj.data(fieldname)|join(','))) %}
31
-                    {% for linked_obj in linked_objs %}
32
-                            {{ edit.display(linked_obj) }}
33
-                            <br/>
34
-                    {% endfor %}
35
-                        </ul></li>
36
-                {% elif obj.data(fieldname) is not none %}
37
-                    <li>{{ fieldname }}
38
-                        <ul>
39
-                        {% set l_classe = fieldvalue.allowed_classes[0] %}
40
-                        {% set linked_objs=l_classe.get(("%s = %s") % (l_classe.uid_fieldname()[0], obj.data(fieldname))) %}
41
-                        {{ edit.display(linked_objs.pop()) }}
42
-                        <br/>
43
-                        </ul>
44
-                    </li>
45
-                {% endif %}
46
-            {% else %}
47
-                <li> {{ fieldname }} : {{ obj.data(fieldname) }} </li>
48
-            {% endif %}
49
-        {% endif %}
50
-    {% endfor %}
51
-</ul>
26
+    {{ show_object.object_ul(obj, 2) }}
52 27
 {% endblock %}

+ 38
- 0
lodel/plugins/webui/templates/macros/show_object.html Просмотреть файл

@@ -0,0 +1,38 @@
1
+<!-- Produce a <li></li> with objects informations -->
2
+{% macro object_ul(leo, max_depth = 0, exclude = []) -%}
3
+    <ul>
4
+        {% if max_depth <= 0 %}
5
+            <!-- No need to go deeper -->
6
+            {% for fname, fvalue in leo.datas(True).items() %}
7
+                <li><em>{{ fname }}</em> : {{fvalue}}</li>
8
+            {%endfor%}
9
+        {% else %}
10
+            {% for fname in leo.fieldnames(True) %}
11
+                {% set fvalue = leo.data(fname) %}
12
+                {% set fdh = leo.data_handler(fname) %}
13
+                {% if fvalue is not none and fdh.is_reference() %}
14
+                    {% if fdh.is_singlereference() %}
15
+                        {% set referenced = fdh.get_referenced(fvalue) %}
16
+                        {% if (referenced.__class__.__name__, referenced.uid) in exclude %}
17
+                            <li><em>{{fname}}</em> : {{fvalue}}</li>
18
+                        {% else %}
19
+                            <li><em>{{fname}}</em> : {{object_ul(referenced, max_depth - 1, exclude + [(leo.__class__.__name__, leo.uid())] )}}</li>
20
+                        {% endif %}
21
+                    {% else %}
22
+                        <li><em>{{fname}}</em> : <ul>
23
+                        {% for referenced in fdh.get_referenced(fvalue) %}
24
+                            {% if (referenced.__class__.__name__, referenced.uid) in exclude %}
25
+                                <li><em>{{fname}}</em> : {{fvalue}}</li>
26
+                            {% else %}
27
+                                <li><em>{{fname}}</em> : {{object_ul(referenced, max_depth - 1, exclude + [(leo.__class__.__name__, leo.uid())] )}}</li>
28
+                            {% endif %}
29
+                        {% endfor %}
30
+                        </ul></li>
31
+                    {% endif %}
32
+                {% else %}
33
+                    <li><em>{{fname}}</em> : {{fvalue}}</li>
34
+                {% endif %}
35
+            {% endfor %}
36
+        {% endif %}
37
+    </ul>
38
+{%- endmacro %}

+ 4
- 2
lodel/settings/settings.py Просмотреть файл

@@ -54,7 +54,7 @@ class MetaSettings(type):
54 54
 # settings.
55 55
 # Here is the conceptual presentation of Settings class initialization stages :
56 56
 #   -# Preloading (sets values like lodel2 library path or the plugins path)
57
-#   -# Ask a @ref lodel.settings.setting_loader.SettingsLoader to load all 
57
+#   -# Ask a @ref lodel.settings.settings_loader.SettingsLoader to load all
58 58
 #configurations files
59 59
 #   -# Fetch the list of plugins in the loaded settings
60 60
 #   -# Merge plugins settings specification with the global lodel settings 
@@ -80,7 +80,7 @@ class Settings(object, metaclass=MetaSettings):
80 80
     
81 81
     ## @brief Instanciate the Settings singleton
82 82
     # @param conf_dir str : The configuration directory
83
-    #@param custom_confspec None | dict : if given overwrite default lodel2
83
+    #@param custom_confspecs None | dict : if given overwrite default lodel2
84 84
     #confspecs
85 85
     def __init__(self, conf_dir, custom_confspecs = None):
86 86
         self.singleton_assert() # check that it is the only instance
@@ -112,6 +112,7 @@ class Settings(object, metaclass=MetaSettings):
112 112
 
113 113
     ##@brief An utility method that raises if the singleton is not in a good
114 114
     # state
115
+    #@param cls
115 116
     #@param expect_instanciated bool : if True we expect that the class is
116 117
     # allready instanciated, else not
117 118
     # @throw RuntimeError
@@ -125,6 +126,7 @@ class Settings(object, metaclass=MetaSettings):
125 126
                 raise RuntimeError("The Settings class is already started")
126 127
 
127 128
     ##@brief Saves a new configuration for section confname
129
+    #@param cls
128 130
     #@param confname is the name of the modified section
129 131
     #@param confvalue is a dict with variables to save
130 132
     #@param validator is a dict with adapted validator

+ 8
- 1
lodel/settings/validator.py Просмотреть файл

@@ -58,6 +58,7 @@ class SettingValidator(object):
58 58
             raise SettingsValidationError(e)
59 59
     
60 60
     ##@brief Register a new validator
61
+    # @param cls SettingValidator
61 62
     # @param name str : validator name
62 63
     # @param callback callable : the function that will validate a value
63 64
     # @param description str
@@ -77,6 +78,7 @@ class SettingValidator(object):
77 78
         return copy.copy(cls._description)
78 79
 
79 80
     ##@brief Create and register a list validator
81
+    # @param cls SettingValidator
80 82
     # @param elt_validator callable : The validator that will be used for validate each elt value
81 83
     # @param validator_name str
82 84
     # @param description None | str
@@ -100,6 +102,7 @@ class SettingValidator(object):
100 102
         return cls(validator_name)
101 103
  
102 104
     ##@brief Create and register a list validator which reads an array and returns a string
105
+    # @param cls SettingValidator
103 106
     # @param elt_validator callable : The validator that will be used for validate each elt value
104 107
     # @param validator_name str
105 108
     # @param description None | str
@@ -121,6 +124,7 @@ class SettingValidator(object):
121 124
         return cls(validator_name)
122 125
     
123 126
     ##@brief Create and register a regular expression validator
127
+    # @param cls SettingValidator
124 128
     # @param pattern str : regex pattern
125 129
     # @param validator_name str : The validator name
126 130
     # @param description str : Validator description
@@ -406,7 +410,10 @@ SettingValidator.create_re_validator(
406 410
 ##@brief Append a piece of confspec
407 411
 #@note orig is modified during the process
408 412
 #@param orig dict : the confspec to update
409
-#@param upd dict : the confspec to add
413
+#@param section str : the name of the section to add
414
+#@param key str : the name of the key to add
415
+#@param validator SettingValidator : The validator to use for this configuration key
416
+#@param default : the default value for this configuration key
410 417
 #@return new confspec
411 418
 def confspec_append(orig, section, key, validator, default):
412 419
     if section not in orig:

+ 2
- 0
lodel/utils/mlstring.py Просмотреть файл

@@ -58,6 +58,7 @@ class MlString(object):
58 58
             self.values[lang] = val
59 59
 
60 60
     ##@brief Checks that given lang is valid
61
+    # @param cls MlString
61 62
     # @param lang str : the lang
62 63
     @classmethod
63 64
     def lang_is_valid(cls, lang):
@@ -75,6 +76,7 @@ class MlString(object):
75 76
         cls.__default_lang = lang
76 77
     
77 78
     ##@brief Return a mlstring loaded from a json string
79
+    # @param cls MlString
78 80
     # @param json_str str : Json string
79 81
     @classmethod
80 82
     def from_json(cls, json_str):

+ 1
- 0
progs/slim/slim.py Просмотреть файл

@@ -281,6 +281,7 @@ def get_pid(name):
281 281
 
282 282
 ##@brief Start an instance
283 283
 #@param names list : instance name list
284
+#@param foreground bool : defines if the starting instance will be executed as a subprocess in the background (if False) or as the main process (if True)
284 285
 def start_instances(names, foreground):
285 286
     pids = get_pids()
286 287
     store_datas = get_store_datas()

+ 34
- 1
scripts/cbl.sh Просмотреть файл

@@ -13,7 +13,7 @@
13 13
 #
14 14
 # Scenario description :
15 15
 #
16
-# mass_creation instance_name iteration_count :
16
+# mass_creation instance_name iteration_count :
17 17
 #	Create iteration_count time a random leobject in given instance_name
18 18
 #	note : do note create relation between objects, only populate content
19 19
 #	
@@ -21,6 +21,12 @@
21 21
 # 	step 2 : loop on creation (using bash function curl_opt_create_CLSNAME)
22 22
 #		that return the POST fields (populated with random values)
23 23
 #
24
+# mass_get instance_name :
25
+#	Create all possible get for an instance
26
+#	step 1 : fetch all classes
27
+#	step 2 : for each class fetch all id
28
+#	step 3 : for all ids generate the gets
29
+#
24 30
 # mass_deletion instance_name iteration_count :
25 31
 #	Foreach non asbtracty class delete iteration_count time an object of
26 32
 #	current class in current instance
@@ -140,6 +146,32 @@ mass_creation() {
140 146
 	rm -v $cls_list_file >&2
141 147
 }
142 148
 
149
+mass_get() {
150
+	#mass get scenario
151
+	#$1 is instance name
152
+	cls_list_file=$(fetch_all_classes $1)
153
+	base_uri=$(_base_uri $1)
154
+
155
+	#Get the site root
156
+	echo "$base_uri/"
157
+	#Get the site class list
158
+	echo "$base_uri/list_classes"
159
+
160
+	for clsname in $(cat $cls_list_file)
161
+	do
162
+		#Get instances list for a class
163
+		echo "$base_uri/show_class?classname=$clsname"
164
+		ids_file=$(fetch_all_ids $1 $clsname)
165
+		for id in $(cat $ids_file)
166
+		do
167
+			#Get details on an instance
168
+			echo "$base_uri/show_object_detailled?classname=${clsname}&lodel_id=$id"
169
+			#Get base informations on an instance
170
+			echo "$base_uri/show_object?classname=${clsname}&lodel_id=$id"
171
+		done
172
+	done
173
+}
174
+
143 175
 mass_link_edit() {
144 176
 	#mass linking & edition scenarion
145 177
 	#$1 is instance name
@@ -376,6 +408,7 @@ get_queries_with_params() {
376 408
 	done | shuf
377 409
 }
378 410
 
411
+get_queries_with_params "mass_get" $instance_list
379 412
 [ "$n_create" -gt 0 ] && get_queries_with_params "mass_creation" $instance_list $n_create
380 413
 [ "$n_edit" -gt 0 ] && get_queries_with_params "mass_link_edit" $instance_list $n_edit
381 414
 [ "$n_delete" -gt 0 ] && get_queries_with_params "mass_deletion" $instance_list $n_delete

+ 15
- 0
tests/datahandlers/test_leobjectsubclassidentifier.py Просмотреть файл

@@ -0,0 +1,15 @@
1
+import unittest
2
+from unittest import mock 
3
+from unittest.mock import patch
4
+
5
+import leapi_dyncode as dyncode
6
+
7
+from lodel.leapi.datahandlers.datas import LeobjectSubclassIdentifier
8
+from lodel.plugins.dummy_datasource.datasource import DummyDatasource
9
+
10
+
11
+class LeobjectSubclassIdentifierTestCase(unittest.TestCase):
12
+    
13
+    def test_throws_error_if_not_internal(self):
14
+        self.failUnlessRaises(RuntimeError, LeobjectSubclassIdentifier, internal=False)
15
+        

+ 32
- 0
tests/datahandlers/test_uniqid.py Просмотреть файл

@@ -0,0 +1,32 @@
1
+import unittest
2
+from unittest import mock 
3
+from unittest.mock import patch
4
+
5
+import leapi_dyncode as dyncode
6
+
7
+from lodel.leapi.datahandlers.datas import UniqID
8
+from lodel.plugins.dummy_datasource.datasource import DummyDatasource
9
+
10
+
11
+class UniqIDTestCase(unittest.TestCase):
12
+    
13
+    def test_construct_data_sets_new_uid_if_none(self):
14
+        sent_uid = None
15
+        mocked_returned_uid = 987654321
16
+        
17
+        with patch.object(DummyDatasource, 'new_numeric_id', return_value=mocked_returned_uid) as mock_method:
18
+            returned_uid = UniqID.construct_data(UniqID, dyncode.Object, 'lodel_id', '', sent_uid)
19
+            
20
+            mock_method.assert_called_once_with(dyncode.Object)
21
+            self.assertEqual(returned_uid, mocked_returned_uid)
22
+            
23
+    def test_construct_data_returns_already_set_uid(self):
24
+        sent_uid = 123456789
25
+        mocked_returned_uid = 987654321
26
+        
27
+        with patch.object(DummyDatasource, 'new_numeric_id', return_value=mocked_returned_uid) as mock_method:
28
+            returned_uid = UniqID.construct_data(UniqID, dyncode.Object, '', '', sent_uid)
29
+
30
+            self.assertEqual(returned_uid, sent_uid)
31
+            mock_method.assert_not_called()     
32
+        

Загрузка…
Отмена
Сохранить