Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/contributed/sumopy/agilepy/lib_base/classman.py
169689 views
1
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
2
# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
3
# SUMOPy module
4
# Copyright (C) 2012-2021 University of Bologna - DICAM
5
# This program and the accompanying materials are made available under the
6
# terms of the Eclipse Public License 2.0 which is available at
7
# https://www.eclipse.org/legal/epl-2.0/
8
# This Source Code may also be made available under the following Secondary
9
# Licenses when the conditions for such availability set forth in the Eclipse
10
# Public License 2.0 are satisfied: GNU General Public License, version 2
11
# or later which is available at
12
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
13
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
14
15
# @file classman.py
16
# @author Joerg Schweizer
17
# @date 2012
18
19
20
# python classman.py
21
22
# TODO:
23
# - store old values in attrcons and recover with undo
24
25
26
# To be or not to be. -- Shakespeare
27
# To do is to be. -- Nietzsche
28
# To be is to do. -- Sartre
29
# Do be do be do. -- Sinatra
30
31
# save with is saved flag
32
# xml mixin
33
# different attrconfig classe (numbers, strings, lists, colors,...)
34
35
36
import types
37
import os
38
import pickle
39
import sys
40
import string
41
import math
42
from collections import OrderedDict
43
from datetime import datetime
44
#import numpy as np
45
import xmlman as xm
46
from logger import Logger
47
from misc import get_inversemap
48
49
##########
50
51
52
# event triggers
53
# plugtype plugcode
54
EVTDEL = 0 # delete attribute
55
EVTSET = 1 # set attribute
56
EVTGET = 2 # get attribute
57
EVTADD = 3 # add/create attribute
58
59
EVTDELITEM = 20 # delete attribute
60
EVTSETITEM = 21 # set attribute
61
EVTGETITEM = 22 # get attribute
62
EVTADDITEM = 23 # add/create attribute
63
64
65
ATTRS_NOSAVE = ('value', 'plugin', '_obj', '_manager', 'get', 'set', 'add',
66
'del', 'delete', 'childs', 'parent', '_attrconfig_id_tab')
67
ATTRS_SAVE = ('ident', '_name', 'managertype', '_info', 'xmltag', '_attrs_nosave')
68
ATTRS_SAVE_TABLE = ('_is_localvalue', 'attrname', '_colconfigs', '_ids', '_inds', '_attrconfigs',
69
'_groups', 'plugin', '_is_indexing', '_index_to_id', '_id_to_index')
70
71
STRUCTS_COL = ('odict', 'array')
72
STRUCTS_SCALAR = ('scalar', 'list', 'matrix', 'scalar.func')
73
74
NUMERICTYPES = (types.BooleanType, types.FloatType, types.IntType, types.LongType, types.ComplexType)
75
STRINGTYPES = (types.StringType, types.UnicodeType)
76
NODATATYPES = (types.FunctionType, types.InstanceType, types.LambdaType)
77
78
79
def save_obj(obj, filename, is_not_save_parent=False):
80
"""
81
Saves python object to a file with filename.
82
Filename may also include absolute or relative path.
83
If operation fails a False is returned and True otherwise.
84
"""
85
# print 'save_obj',is_not_save_parent,filename,obj.parent
86
try:
87
f = open(filename, 'wb')
88
except:
89
print 'WARNING in save: could not open', filename
90
return False
91
92
if is_not_save_parent:
93
parent = obj.parent
94
obj.parent = None
95
# print ' before',is_not_save_parent,parent,obj.parent
96
pickle.dump(obj, f, protocol=2)
97
f.close()
98
# set all objects and attrubutes to unsaved again
99
# obj.set_unsaved()
100
# no, decided to eliminate _is_saved restriction
101
# print ' after',is_not_save_parent,parent,obj.parent
102
if is_not_save_parent:
103
obj.parent = parent
104
return True
105
106
107
def load_obj(filename, parent=None, is_throw_error=False):
108
"""
109
Reads python object from a file with filename and returns object.
110
Filename may also include absolute or relative path.
111
If operation fails a None object is returned.
112
"""
113
print 'load_obj', filename
114
115
if is_throw_error:
116
f = open(filename, 'rb')
117
else:
118
try:
119
f = open(filename, 'rb')
120
except:
121
print 'WARNING in load_obj: could not open', filename
122
return None
123
124
# try:
125
# print ' pickle.load...'
126
obj = pickle.load(f)
127
f.close()
128
129
# init_postload_internal is to restore INTERNAL states from INTERNAL states
130
# print 'load_obj->init_postload_internal',obj.ident
131
obj.init_postload_internal(parent)
132
# print ' after init_postload_internal obj.parent',obj.parent
133
134
# init_postload_external is to restore INTERNAL states from EXTERNAL states
135
# such as linking
136
#obj.init_postload_external(is_root = True)
137
obj.init_postload_external()
138
139
# _init4_ is to do misc stuff when everything is set
140
# obj._init4_config()
141
142
return obj
143
144
# class ObjXmlMixin:
145
146
147
# class AttrXmlMixin:
148
149
150
class Plugin:
151
152
def __init__(self, obj, is_enabled=True):
153
self._obj = obj # this can be either attrconf or main object
154
self._events = {}
155
self._has_events = False
156
self._is_enabled = is_enabled
157
158
def get_obj(self):
159
return self._obj
160
161
def unplug(self):
162
del self._events
163
self._events = {}
164
self._has_events = False
165
166
def add_event(self, trigger, function):
167
"""
168
Standard plug types are automatically set but the system:
169
170
"""
171
if not self._events.has_key(trigger):
172
self._events[trigger] = []
173
self._events[trigger].append(function)
174
self._has_events = True
175
176
def del_event(self, trigger):
177
del self._events[trigger]
178
if len(self._events) == 0:
179
self._has_events = False
180
181
def enable(self, is_enabled=True):
182
self._is_enabled = is_enabled
183
184
def exec_events(self, trigger):
185
if self._has_events & self._is_enabled:
186
# print '**PuginMixin.exec_events',trigger,(EVTGETITEM,EVTGET)
187
# if trigger!=EVTGET:
188
# print ' call set_modified',self._obj
189
# self._obj.set_modified(True)
190
191
for function in self._events.get(trigger, []):
192
function(self._obj)
193
194
def exec_events_attr(self, trigger, attrconfig):
195
if self._has_events & self._is_enabled:
196
# print '**PuginMixin.exec_events',trigger,(EVTGETITEM,EVTGET)
197
# if trigger!=EVTGET:
198
# print ' call set_modified',self._obj
199
# self._obj.set_modified(True)
200
201
for function in self._events.get(trigger, []):
202
function(self._obj, attrconfig)
203
204
def exec_events_ids(self, trigger, ids):
205
"""
206
Executes all functions assigned for this trigger for multiple ids.
207
"""
208
if self._has_events & self._is_enabled:
209
# print '**ArrayConf._execute_events_keys',trigger,ids
210
# print ' _events',self._events
211
212
for function in self._events.get(trigger, []):
213
function(self._obj, ids)
214
215
216
class AttrConf:
217
"""
218
Contains additional information on the object's attribute.
219
"""
220
221
def __init__(self, attrname, default,
222
groupnames=[], perm='rw',
223
is_save=True,
224
# is_link = False, # define link class
225
is_copy=True,
226
name='', info='',
227
unit='',
228
xmltag=None,
229
xmlsep=' ',
230
xmlmap=None,
231
is_plugin=False,
232
struct='scalar',
233
metatype='',
234
is_returnval=True,
235
**attrs):
236
# if struct == 'None':
237
# if hasattr(default, '__iter__'):
238
# struct = 'scalar'
239
# else:
240
# struct = 'list'
241
242
# these states will be saved and reloaded
243
self.attrname = attrname
244
self.groupnames = groupnames
245
self.metatype = metatype
246
self.struct = struct
247
248
self._default = default
249
250
self._is_save = is_save # will be set properly in set_manager
251
self._is_copy = is_copy
252
self._is_localvalue = True # value stored locally, set in set_manager
253
self._is_returnval = is_returnval
254
self._unit = unit
255
self._info = info
256
self._name = name
257
self._perm = perm
258
259
# states below need to be resored after load
260
self._manager = None # set later by attrsman , necessary?
261
self._obj = None # parent object, set later by attrsman
262
263
self._is_modified = False
264
self._is_saved = False
265
266
self.init_plugin(is_plugin)
267
# self._init_xml(xmltag)
268
self.set_xmltag(xmltag, xmlsep, xmlmap)
269
270
# set rest of attributes passed as keyword args
271
# no matter what they are used for
272
for attr, value in attrs.iteritems():
273
setattr(self, attr, value)
274
275
def is_save(self):
276
return self._is_save
277
278
def set_save(self, is_save):
279
if is_save:
280
self._manager.do_save_attr(self.attrname)
281
else:
282
self._manager.do_not_save_attr(self.attrname)
283
284
def add_groupnames(self, groupnames):
285
self.groupnames = list(set(self.groupnames+groupnames))
286
self._manager.insert_groupnames(self)
287
288
def del_groupname(self, groupname):
289
if groupname in self.groupnames:
290
self.groupnames.remove(groupname)
291
292
# do this update in any case to be sure
293
# it disappears in the centralized database
294
self._manager.del_groupname(self)
295
296
def has_group(self, groupname):
297
return groupname in self.groupnames
298
299
def enable_plugin(self, is_enabled=True):
300
if self.plugin is not None:
301
self.plugin.enable(is_enabled)
302
303
def get_metatype(self):
304
return self.metatype
305
306
def init_plugin(self, is_plugin):
307
if is_plugin:
308
self.plugin = Plugin(self)
309
self.set = self.set_plugin
310
self.get = self.get_plugin
311
else:
312
self.plugin = None
313
314
# def _init_xml(self,xmltag=None):
315
# if xmltag is not None:
316
# self.xmltag = xmltag
317
# else:
318
# self.xmltag = self.attrname
319
320
def set_xmltag(self, xmltag, xmlsep=' ', xmlmap=None):
321
self.xmltag = xmltag
322
self.xmlsep = xmlsep
323
self.xmlmap = xmlmap
324
325
def get_value_from_xmlattr(self, xmlattrs):
326
"""
327
Return a value of the correct data type
328
from the xml attribute object
329
330
If this configuration is not found in xmlattrs
331
then None is returned.
332
"""
333
if (self.xmltag is not None):
334
if xmlattrs.has_key(self.xmltag):
335
return self.get_value_from_string(xmlattrs[self.xmltag])
336
else:
337
return None
338
339
def get_value_from_string(self, s, sep=','):
340
"""
341
Returns the attribute value from a string in the correct type.
342
"""
343
344
if self.metatype == 'color':
345
return xm.parse_color(s, sep)
346
347
# TODO: allow arrays
348
# elif hasattr(val, '__iter__'):
349
# if len(val)>0:
350
# if hasattr(val[0], '__iter__'):
351
# # matrix
352
# fd.write(xm.mat(self.xmltag,val))
353
# else:
354
# # list
355
# fd.write(xm.arr(self.xmltag,val,self.xmlsep))
356
# else:
357
# # empty list
358
# #fd.write(xm.arr(self.xmltag,val))
359
# # don't even write empty lists
360
# pass
361
362
elif self.xmlmap is not None:
363
imap = get_inversemap(self.xmlmap)
364
# print 'get_value_from_string',s,imap
365
if imap.has_key(s):
366
return imap[s]
367
else:
368
return self.get_numvalue_from_string(s)
369
370
else:
371
return self.get_numvalue_from_string(s)
372
373
def get_numvalue_from_string(self, s, valtype=None):
374
if valtype is None:
375
t = type(self._default)
376
else:
377
t = valtype
378
379
if t in (types.UnicodeType, types.StringType):
380
return s
381
382
elif t in (types.UnicodeType, types.StringType):
383
return s
384
385
elif t in (types.LongType, types.IntType):
386
return int(s)
387
388
elif t in (types.FloatType, types.ComplexType):
389
return float(s)
390
391
elif t == types.BooleanType: # use default and hope it is no a numpy bool!!!
392
if s in ('1', 'True'):
393
return True
394
else:
395
return False
396
# 'MethodType', 'ModuleType', 'NoneType', 'NotImplementedType', 'ObjectType'
397
else:
398
return None # unsuccessful
399
400
def write_xml(self, fd):
401
if self.xmltag is not None:
402
self._write_xml_value(self.get_value(), fd)
403
404
def _write_xml_value(self, val, fd):
405
# print 'write_xml',self.xmltag,'is array',hasattr(val, '__iter__'),'xmlmap',self.xmlmap
406
if self.metatype == 'color':
407
fd.write(xm.color(self.xmltag, val))
408
409
elif hasattr(val, '__iter__'):
410
if len(val) > 0:
411
if hasattr(val[0], '__iter__'):
412
# matrix
413
fd.write(xm.mat(self.xmltag, val))
414
else:
415
# list
416
fd.write(xm.arr(self.xmltag, val, self.xmlsep))
417
else:
418
# empty list
419
# fd.write(xm.arr(self.xmltag,val))
420
# don't even write empty lists
421
pass
422
423
elif self.xmlmap is not None:
424
if self.xmlmap.has_key(val):
425
fd.write(xm.num(self.xmltag, self.xmlmap[val]))
426
else:
427
fd.write(xm.num(self.xmltag, val))
428
429
elif hasattr(self, 'choices'):
430
if type(self.choices) == types.ListType:
431
fd.write(xm.num(self.xmltag, val))
432
else:
433
# print '_write_xml_value',self.attrname
434
# print ' val,self.choices.values()',val,self.choices.values()
435
i = self.choices.values().index(val)
436
fd.write(xm.num(self.xmltag, self.choices.keys()[i]))
437
438
elif type(self._default) == types.BooleanType: # use default and hope it is no a numpy bool!!!
439
if val:
440
fd.write(xm.num(self.xmltag, 1))
441
else:
442
fd.write(xm.num(self.xmltag, 0))
443
444
elif type(self._default) in (types.UnicodeType, types.StringType):
445
if len(val) > 0:
446
fd.write(xm.num(self.xmltag, val))
447
448
else:
449
# scalar number or string
450
fd.write(xm.num(self.xmltag, val))
451
452
def get_name(self):
453
return self._name
454
455
def is_modified(self):
456
# print 'is_modified', self.attrname, self._is_modified
457
return self._is_modified
458
459
def set_modified(self, is_modified):
460
self._is_modified = is_modified
461
462
def set_manager(self, manager):
463
"""
464
Method to set manager to attribute configuration object.
465
This is either attribute manager or table manager.
466
Used by add method of AttrManager
467
"""
468
self._manager = manager
469
self._is_localvalue = manager.is_localvalue()
470
self.set_save(self._is_save)
471
472
def get_manager(self):
473
"""
474
Method to get manager to attribute configuration object.
475
"""
476
return self._manager
477
478
def set_obj(self, obj):
479
"""
480
Method to set instance of managed object.
481
Used by add method of AttrManager
482
"""
483
self._obj = obj
484
485
def get_obj(self):
486
return self._obj
487
488
def get(self):
489
# return attribute, overridden with indexing for array and dict struct
490
return self.get_value()
491
492
def set(self, value):
493
# set attribute, overridden with indexing for array and dict struct
494
if value != self.get_value():
495
self.set_value(value)
496
self._is_modified = True
497
return value
498
499
def get_plugin(self):
500
"""
501
Default get method with plugin for scalar attrs
502
"""
503
# return attribute, overridden with indexing for array and dict struct
504
self.plugin.exec_events(EVTGET)
505
506
return self.get_value()
507
508
def set_plugin(self, value):
509
"""
510
Default set method with plugin for scalar attrs
511
"""
512
# set attribute, overridden with indexing for array and dict struct
513
if value != self.get_value():
514
self.set_value(value)
515
self._is_modified = True
516
self.plugin.exec_events(EVTSET)
517
518
return value
519
520
def set_default(self, value):
521
self._default = value
522
523
def get_default(self):
524
return self._default
525
526
def get_init(self):
527
"""
528
Returns initialization of attribute.
529
Usually same as get_default for scalars.
530
Overridden by table configuration classes
531
"""
532
value = self.get_default()
533
# store locally if required
534
if self._is_localvalue:
535
self.value = value
536
return value
537
538
def reset(self):
539
if self._is_localvalue:
540
self.value = self.get_default()
541
else:
542
setattr(self._obj, self.attrname, self.get_default())
543
544
def clear(self):
545
self.reset()
546
547
# def is_tableattr(self):
548
# return self.struct in ('dict','array','list')
549
550
def set_perm(self, perm):
551
self._perm = perm
552
553
def get_perm(self):
554
return self._perm
555
556
def is_returnval(self):
557
if hasattr(self, '_is_returnval'): # for back compatibility
558
return self._is_returnval
559
else:
560
return True
561
562
def is_readonly(self):
563
return 'w' not in self._perm
564
565
def is_writable(self):
566
return 'w' in self._perm
567
568
def is_editable(self):
569
"""Can attribute be edited """
570
return 'e' in self._perm
571
572
def has_unit(self):
573
return self._unit != ''
574
575
def has_info(self):
576
return self.get_info() is not None
577
578
def is_colattr(self):
579
return hasattr(self, '__getitem__')
580
581
def get_info(self):
582
if self._info is None:
583
return self.__doc__
584
else:
585
return self._info
586
587
def format_unit(self, show_parentesis=False):
588
if self._unit in ('', None):
589
return ''
590
if show_parentesis:
591
return '[%s]' % self._unit
592
else:
593
return '%s' % self._unit
594
595
def format_value(self, show_unit=False, show_parentesis=False):
596
if show_unit:
597
unit = ' '+self.format_unit(show_parentesis)
598
else:
599
unit = ''
600
# return repr(self.get_value())+unit
601
v = self.get_value()
602
# print 'format_value',self.attrname,v,type(v)
603
604
if not hasattr(v, '__iter__'):
605
# print ' ',hasattr(self, 'digits_fraction'),(not math.isnan(v)),(not math.isinf(v))
606
if hasattr(self, 'digits_fraction'):
607
if (not math.isnan(v)) & (not math.isinf(v)):
608
printformat = "%."+str(self.digits_fraction)+"f"
609
return printformat % v+unit
610
else:
611
return str(v)+unit
612
else:
613
return str(v)+unit
614
else:
615
return str(v)+unit
616
617
def format_symbol(self, show_parentesis=True):
618
if hasattr(self, 'symbol'):
619
symbol = self.symbol
620
else:
621
symbol = self._name
622
623
return symbol+' '+self.format_unit(show_parentesis=show_parentesis)
624
625
####
626
627
def get_value(self):
628
# always return attribute, no indexing, no plugin
629
if self._is_localvalue:
630
return self.value
631
else:
632
return getattr(self._obj, self.attrname)
633
634
def set_value(self, value):
635
# set entire attribute, no indexing, no plugin
636
# print 'AttrConf.set_value',self.attrname, self._is_localvalue, value, type(value)
637
if self._is_localvalue:
638
self.value = value
639
else:
640
return setattr(self._obj, self.attrname, value)
641
642
def predelete(self):
643
"""
644
Cleanup operations before deleting
645
"""
646
if self._is_localvalue:
647
del self.value # delete value
648
else:
649
del self._obj.__dict__[self.attrname] # delete value
650
651
# def init_presave_internal(self, man, obj):
652
# pass
653
# not a good idea to delete links, plugins here
654
655
# def save_value(self, state):
656
# """
657
# Save attribute value of managed object to state dict.
658
#
659
# move this into __getstate__
660
#
661
# restore value in _obj during postllad_external
662
#
663
# make _getstate_ for speecific save
664
# """
665
# #print 'save_value',self.attrname,self._is_save, self._is_localvalue,
666
# #
667
# # Attention can be called fron __getstate__ of obj if _is_localvalue=False
668
# # or from __getstate__ of attribute config if _is_localvalue=True
669
670
def _getstate_specific(self, state):
671
"""
672
Called by __getstate__ to add/change specific states,
673
before returning states.
674
To be overridden.
675
"""
676
pass
677
678
def __getstate__(self):
679
# print 'AttrConf.__getstate__',self.get_obj().format_ident_abs(),self.attrname
680
# print ' self.__dict__=\n',self.__dict__.keys()
681
if self._is_saved:
682
# this message indicates a loop!!
683
print 'WARNING in __getstate__: Attribute already saved:', self.get_obj().format_ident_abs(), self.attrname
684
state = {}
685
for attr in self.__dict__.keys():
686
687
if attr == 'plugin':
688
plugin = self.__dict__[attr]
689
if plugin is not None:
690
state[attr] = True
691
else:
692
state[attr] = False
693
694
elif attr not in ATTRS_NOSAVE:
695
state[attr] = self.__dict__[attr]
696
697
if self._is_save:
698
self._is_modified = False
699
state['value'] = self.get_value()
700
701
self._getstate_specific(state)
702
# print ' state',state
703
return state
704
705
def __setstate__(self, state):
706
# print '__setstate__',self
707
708
# this is always required, but will not be saved
709
self.plugins = {}
710
711
for attr in state.keys():
712
# print ' state key',attr, state[attr]
713
# done in init_postload_internal...
714
# if attr=='plugin':
715
# if state[attr]==True:
716
# self.__dict__[attr] = Plugin(self)
717
# else:
718
# self.__dict__[attr]= None
719
# else:
720
self.__dict__[attr] = state[attr]
721
722
def init_postload_internal(self, man, obj):
723
# print 'AttrConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'obj:',obj.ident
724
725
self.set_manager(man)
726
self.set_obj(obj)
727
self.init_plugin(self.plugin)
728
729
# set initial values for unsafed attributes
730
if not self._is_save:
731
self.set_value(self.get_init())
732
else:
733
if self._is_localvalue:
734
# OK self.value already set in __setstate__
735
pass
736
else:
737
setattr(self._obj, self.attrname, self.value) # TODO: could be made nicer with method
738
del self.value # no longer needed
739
740
# this attribute became compulsory
741
if not hasattr(self, 'xmlmap'):
742
self.xmlmap = None
743
744
# print ' check',hasattr(self,'value')
745
# print ' value=',self.get_value()
746
self._is_saved = False
747
748
def init_postload_external(self):
749
pass
750
751
752
class NumConf(AttrConf):
753
"""
754
Contains additional information on the object's attribute.
755
Here specific number related attributes are defined.
756
"""
757
758
def __init__(self, attrname, default,
759
digits_integer=None, digits_fraction=None,
760
minval=None, maxval=None,
761
**kwargs):
762
self.min = minval
763
self.max = maxval
764
self.digits_integer = digits_integer
765
self.digits_fraction = digits_fraction
766
767
AttrConf.__init__(self, attrname, default, metatype='number',
768
**kwargs
769
)
770
771
772
class ListConf(AttrConf):
773
"""
774
Specifies a list of objects.
775
Objects may be editable or selectable in the GUI
776
"""
777
778
def __init__(self, attrname, default,
779
sep=',', valtype=None, is_fixedlength=False,
780
perm='rw', **kwargs):
781
#self._is_child = is_child
782
if valtype is None:
783
if len(default) > 0:
784
valtype = type(default[0])
785
else:
786
valtype = types.UnicodeType
787
788
AttrConf.__init__(self, attrname, default,
789
struct='scalar',
790
metatype='list',
791
sep=sep,
792
valtype=valtype,
793
is_fixedlength=is_fixedlength,
794
perm=perm,
795
**kwargs
796
)
797
798
def get_value_from_string(self, s, sep=None):
799
"""
800
Returns the attribute value from a string in the correct type.
801
"""
802
value = []
803
for val in s.split(self.sep):
804
value.append(self.get_numvalue_from_string(val, valtype=self.valtype))
805
806
return value
807
808
809
class ObjConf(AttrConf):
810
"""
811
Contains additional information on the object's attribute.
812
Configures Pointer to another object .
813
This other object must have an ident.
814
it can be either a child (then it will be saved)
815
or a link (then only the id will saved)
816
If it is a child the is_child = True (default value)
817
"""
818
819
def __init__(self, valueobj, is_child=True, **kwargs):
820
attrname = valueobj.get_ident()
821
self._is_child = is_child
822
AttrConf.__init__(self, attrname, valueobj,
823
struct='scalar',
824
metatype='obj',
825
perm='r',
826
**kwargs
827
)
828
829
def set_obj(self, obj):
830
"""
831
Method to set instance of managed object.
832
Used by add method of AttrManager
833
"""
834
# print 'ObjConf.set_obj',self.attrname,obj.ident
835
AttrConf.set_obj(self, obj)
836
837
if self._is_child:
838
# tricky: during first initialization
839
# child instance is stored in default
840
obj.set_child(self)
841
842
def predelete(self):
843
AttrConf.predelete(self)
844
if self._is_child:
845
self.get_obj().del_child(self.attrname)
846
847
def reset(self):
848
if self._is_child:
849
self.get_value().reset()
850
851
def clear(self):
852
if self._is_child:
853
self.get_value().clear()
854
855
def is_child(self):
856
return self._is_child
857
858
def _getstate_specific(self, state):
859
"""
860
Called by __getstate__ to add/change specific states,
861
before returning states.
862
To be overridden.
863
"""
864
865
# print 'ObjConf._getstate_specific',self.attrname,self._is_child,self._is_save
866
if self._is_save:
867
if self._is_child:
868
# OK self.value already set in
869
pass
870
else:
871
# print ' remove object reference from value and create ident'
872
state['value'] = None
873
if self.get_value() is not None:
874
# print ' found object',self.get_value().get_ident_abs()
875
state['_ident_value'] = self.get_value().get_ident_abs()
876
else:
877
print 'WARNING in ObjConf._getstate_specific', self.attrname, 'lost linked object'
878
state['_ident_value'] = []
879
# print ' ',
880
881
def is_modified(self):
882
# if self._is_child
883
#is_modified = self.get_value().is_modified()
884
# print 'is_modified', self.attrname, is_modified
885
return self.get_value().is_modified()
886
887
def set_modified(self, is_modified):
888
if self._is_child:
889
self.get_value().set_modified(is_modified)
890
891
def write_xml(self, fd):
892
"""
893
Objects are not written here, but in write_xml of the parent obj.
894
"""
895
pass
896
897
def init_postload_internal(self, man, obj):
898
# print 'ObjConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'parent obj:',obj.ident
899
900
AttrConf.init_postload_internal(self, man, obj)
901
if self._is_child:
902
# print ' make sure children get initialized'
903
# self.get_value().init_postload_internal(obj)
904
# print ' call init_postload_internal of',self.get_value().ident,self.get_value(),self.get_value().__class__,self.get_value().init_postload_internal
905
self.get_value().init_postload_internal(obj)
906
907
def init_postload_external(self):
908
# print 'ObjConf.init_postload_external',self.attrname,self._is_child
909
if self._is_child:
910
# restore normally
911
AttrConf.init_postload_external(self)
912
self.get_value().init_postload_external()
913
else:
914
# Substitute absolute ident with link object.
915
# Called from init_postload_external of attrsman during load_obj
916
#
917
ident_abs = self._ident_value
918
if len(ident_abs) > 0:
919
# print 'reset_linkobj',self.attrname,ident_abs
920
obj = self.get_obj()
921
rootobj = obj.get_root()
922
# print ' rootobj',rootobj.ident
923
linkobj = rootobj.get_obj_from_ident(ident_abs)
924
# print ' linkobj',linkobj.ident
925
self.set_value(linkobj)
926
else:
927
print 'WARNING in ObjConf._getstate_specific', self.attrname, 'lost linked object'
928
self.set_value(BaseObjman('lost_object'))
929
930
# def get_valueobj(self):
931
# """
932
# This is called by get_childobj to retrive the child instance.
933
# """
934
# return self.get_value()
935
936
def get_name(self):
937
return self.get_value().get_name()
938
939
def get_info(self):
940
return self.get_value().__doc__
941
942
def format_value(self, show_unit=False, show_parentesis=False):
943
return repr(self.get_value())
944
945
946
class FuncConf(AttrConf):
947
"""
948
Configures a function.
949
The function with name funcname must be a method of the object.
950
Default value is used to specify the type of output.
951
"""
952
953
def __init__(self, attrname, funcname, exampleoutput, struct='scalar.func', perm='r', **kwargs):
954
self.funcname = funcname
955
956
AttrConf.__init__(self, attrname, exampleoutput,
957
struct=struct,
958
perm=perm,
959
is_save=False,
960
**kwargs
961
)
962
963
def set_obj(self, obj):
964
AttrConf.set_obj(self, obj)
965
if self._info == '':
966
self._info = getattr(self._obj, self.funcname).__doc__
967
968
def get_value(self):
969
# print 'get_value',self.attrname
970
# always return attribute, no indexing, no plugin
971
return getattr(self._obj, self.funcname)()
972
# if self._is_localvalue:
973
# return self.value
974
# else:
975
# return getattr(self._obj, self.attrname)
976
977
def get_function(self):
978
# print 'get_function',self.attrname
979
return getattr(self._obj, self.funcname)
980
981
def set_value(self, value):
982
# set entire attribute, no indexing, no plugin
983
# print 'AttrConf.set_value',self.attrname, self._is_localvalue, value, type(value)
984
# this will run the function and return a value
985
return self.get_function()
986
987
def is_modified(self):
988
return False
989
990
def reset(self):
991
pass
992
993
def clear(self):
994
pass
995
996
997
class Indexing:
998
"""
999
Mixing to allow any column attribute to be used as index.
1000
"""
1001
1002
def _init_indexing(self):
1003
"""
1004
Init Indexing management attributes.
1005
"""
1006
1007
self._index_to_id = {} # OrderedDict()
1008
1009
# this updates index if values already exist
1010
if hasattr(self, 'value'):
1011
ids = self.get_obj().get_ids()
1012
self.add_indices(ids, self[ids])
1013
1014
def reset_index(self):
1015
self._init_indexing()
1016
1017
def get_indexmap(self):
1018
return self._index_to_id
1019
1020
def get_id_from_index(self, index):
1021
return self._index_to_id[index]
1022
1023
def has_indices(self, indices):
1024
ans = len(indices)*[False]
1025
for i in range(len(indices)):
1026
if self._index_to_id.has_key(indices[i]):
1027
ans[i] = True
1028
1029
return ans
1030
1031
def has_index(self, index):
1032
return self._index_to_id.has_key(index)
1033
1034
def get_ids_from_indices(self, indices):
1035
ids = len(indices)*[0]
1036
for i in range(len(indices)):
1037
# if not self._index_to_id.has_key(indices[i]):
1038
# print 'WARNING from get_ids_from_indices: no index',indices[i]
1039
# print self._index_to_id
1040
ids[i] = self._index_to_id[indices[i]]
1041
return ids
1042
1043
def get_ids_from_indices_save(self, indices):
1044
ids = len(indices)*[0]
1045
for i in range(len(indices)):
1046
if not self._index_to_id.has_key(indices[i]):
1047
ids[i] = -1
1048
else:
1049
ids[i] = self._index_to_id[indices[i]]
1050
return ids
1051
1052
# use set instead of add
1053
1054
def add_indices(self, ids, indices):
1055
for _id, index in zip(ids, indices):
1056
self.add_index(_id, index)
1057
1058
def add_index(self, _id, index):
1059
self._index_to_id[index] = _id
1060
1061
def rebuild_indices(self):
1062
for idx in self._index_to_id.keys():
1063
del self._index_to_id[idx]
1064
ids = self.get_obj().get_ids()
1065
self.add_indices(ids, self[ids])
1066
1067
def del_indices(self, ids):
1068
1069
for _id in ids:
1070
self.del_index(_id)
1071
1072
def set_index(self, _id, index):
1073
# print 'set_index',self.attrname,_id, index
1074
# print ' B_index_to_id',self._index_to_id
1075
self.del_index(_id)
1076
self.add_index(_id, index)
1077
# print ' A_index_to_id',self._index_to_id
1078
1079
def set_indices(self, ids, indices):
1080
self.del_indices(ids)
1081
self.add_indices(ids, indices)
1082
1083
def del_index(self, _id):
1084
index = self[_id]
1085
# when index is added (with set) no previous index value exists
1086
if self._index_to_id.has_key(index):
1087
del self._index_to_id[index]
1088
1089
def get_ids_sorted(self):
1090
# print 'get_ids_sorted',self.value
1091
# print ' _index_to_id',self._index_to_id
1092
# print ' sorted',sorted(self._index_to_id.iteritems())
1093
return OrderedDict(sorted(self._index_to_id.iteritems())).values()
1094
1095
# def indexset(self, indices, values):
1096
# no! set made with respective attribute
1097
# print 'indexset',indices
1098
# print ' ids=',self.get_ids_from_indices(indices)
1099
# print ' values=',values
1100
# self[self.get_ids_from_indices(indices)] = values
1101
1102
1103
class ColConf(Indexing, AttrConf):
1104
"""
1105
Basic column configuration.
1106
Here an ordered dictionary is used to represent the data.
1107
#>>> from collections import OrderedDict
1108
#>>> spam = OrderedDict([('s',(1,2)),('p',(3,4)),('a',(5,6)),('m',(7,8))])
1109
>>> spam.values()
1110
1111
"""
1112
# def __init__(self, **attrs):
1113
# print 'ColConf',attrs
1114
1115
def __init__(self, attrname, default, is_index=False, **attrs):
1116
# print 'ColConf',attrs
1117
self._is_index = is_index
1118
AttrConf.__init__(self, attrname, default,
1119
struct='odict',
1120
**attrs)
1121
1122
if is_index:
1123
self._init_indexing()
1124
1125
def is_index(self):
1126
return self._is_index
1127
1128
def get_defaults(self, ids):
1129
# create a list, should work for all types and dimensions
1130
# default can be scalar or an array of any dimension
1131
# print '\n\nget_defaults',self.attrname,ids,self.get_default()
1132
values = []
1133
for _id in ids:
1134
values.append(self.get_default())
1135
# len(ids)*self.get_default() # makes links, not copies
1136
return values
1137
1138
def get_init(self):
1139
"""
1140
Returns initialization of attribute.
1141
Usually same as get_default for scalars.
1142
Overridden by table configuration classes
1143
"""
1144
ids = self._manager.get_ids()
1145
1146
# print '\n\nget_init',self.attrname,ids
1147
values = self.get_defaults(ids)
1148
i = 0
1149
odict = OrderedDict()
1150
for _id in ids:
1151
odict[_id] = values[i]
1152
i += 1
1153
# store locally if required
1154
if self._is_localvalue:
1155
self.value = odict
1156
# pass on to calling instance
1157
# in this cas the data is stored under self._obj
1158
return odict
1159
1160
def reset(self):
1161
# this reset works also for np arrays!
1162
odict = self.get_init()
1163
if not self._is_localvalue:
1164
setattr(self._obj, self.attrname, odict)
1165
if self._is_index:
1166
self.reset_index()
1167
1168
def init_plugin(self, is_plugin):
1169
if is_plugin:
1170
self.plugin = Plugin(self)
1171
self.set = self.set_plugin
1172
self.get = self.get_plugin
1173
self.add = self.add_plugin
1174
self.delete = self.delete_plugin
1175
else:
1176
self.plugin = None
1177
1178
def write_xml(self, fd, _id):
1179
if self.xmltag is not None:
1180
self._write_xml_value(self[_id], fd)
1181
1182
def __delitem__(self, ids):
1183
# print ' before=\n',self.__dict__[attr]
1184
#attr = self.attrconf.get_attr()
1185
if hasattr(ids, '__iter__'):
1186
if self._is_index:
1187
self.del_indices(ids)
1188
1189
array = self.get_value()
1190
for _id in ids:
1191
del array[_id]
1192
1193
else:
1194
if self._is_index:
1195
self.del_index(ids)
1196
1197
del self.get_value()[ids]
1198
1199
def delete_item(self, _id):
1200
# print ' before=\n',self.__dict__[attr]
1201
#attr = self.attrconf.get_attr()
1202
del self.get_value()[_id]
1203
1204
def __getitem__(self, ids):
1205
# print '__getitem__',key
1206
if hasattr(ids, '__iter__'):
1207
items = len(ids)*[None]
1208
i = 0
1209
array = self.get_value()
1210
for _id in ids:
1211
items[i] = array[_id]
1212
i += 1
1213
return items
1214
else:
1215
return self.get_value()[ids]
1216
1217
def __setitem__(self, ids, values):
1218
# print '__setitem__',ids,values,type(self.get_value())
1219
if hasattr(ids, '__iter__'):
1220
if self._is_index:
1221
self.set_indices(ids, values) # must be set before setting new value
1222
i = 0
1223
array = self.get_value()
1224
for _id in ids:
1225
array[_id] = values[i]
1226
i += 1
1227
# if self._is_index:
1228
# self.add_indices(ids, values)
1229
else:
1230
1231
if self._is_index:
1232
self.set_index(ids, values) # must be set before setting new value
1233
self.get_value()[ids] = values
1234
1235
# if self._is_index:
1236
# self.add_index(ids, values)
1237
1238
def add(self, ids, values=None):
1239
if not hasattr(ids, '__iter__'):
1240
_ids = [ids]
1241
if values is not None:
1242
_values = [values]
1243
else:
1244
_ids = ids
1245
_values = values
1246
1247
if values is None:
1248
_values = self.get_defaults(_ids)
1249
1250
# print 'add ids, _values',ids, _values
1251
# trick to prevent updating index before value is added
1252
if self._is_index:
1253
is_index_backup = True
1254
self._is_index = False
1255
else:
1256
is_index_backup = False
1257
1258
self[_ids] = _values
1259
1260
if is_index_backup:
1261
self._is_index = True
1262
self.add_indices(_ids, _values)
1263
1264
self._is_modified = True
1265
1266
def add_plugin(self, ids, values=None):
1267
if not hasattr(ids, '__iter__'):
1268
_ids = [ids]
1269
if values is not None:
1270
_values = [values]
1271
else:
1272
_ids = ids
1273
_values = values
1274
1275
# print 'add ids, _values',ids, _values
1276
if values is None:
1277
_values = self.get_defaults(_ids)
1278
# trick to prevent updating index before value is added
1279
if self._is_index:
1280
is_index_backup = True
1281
self._is_index = False
1282
else:
1283
is_index_backup = False
1284
1285
self[_ids] = _values
1286
1287
if is_index_backup:
1288
self._is_index = True
1289
self.add_indices(_ids, _values)
1290
1291
self._is_modified = True
1292
1293
if self.plugin:
1294
self.plugin.exec_events_ids(EVTADDITEM, _ids)
1295
1296
def get(self, ids):
1297
"""
1298
Central function to get the attribute value associated with ids.
1299
should be overridden by specific array configuration classes
1300
"""
1301
return self[ids]
1302
1303
def get_plugin(self, ids):
1304
"""
1305
Central function to get the attribute value associated with ids.
1306
should be overridden by specific array configuration classes
1307
"""
1308
if self._plugin:
1309
if not hasattr(ids, '__iter__'):
1310
self.plugin.exec_events_ids(EVTGETITEM, [ids])
1311
else:
1312
self.plugin.exec_events_ids(EVTGETITEM, ids)
1313
return self[ids]
1314
1315
def set(self, ids, values):
1316
"""
1317
Returns value of array element for all ids.
1318
"""
1319
1320
self[ids] = values
1321
self._is_modified = True
1322
# print 'set',self.attrname
1323
if self._is_index:
1324
self.set_indices(ids, values)
1325
1326
def set_plugin(self, ids, values):
1327
"""
1328
Returns value of array element for all ids.
1329
"""
1330
self[ids] = values
1331
self._is_modified = True
1332
# print 'set',self.attrname
1333
1334
if self.plugin:
1335
if not hasattr(ids, '__iter__'):
1336
self.plugin.exec_events_ids(EVTSETITEM, [ids])
1337
else:
1338
self.plugin.exec_events_ids(EVTSETITEM, ids)
1339
if self._is_index:
1340
self.set_indices(ids, values)
1341
1342
def delete(self, ids):
1343
"""
1344
removes key from array structure
1345
To be overridden
1346
"""
1347
del self[ids]
1348
self._is_modified = True
1349
1350
def delete_plugin(self, ids):
1351
"""
1352
removes key from array structure
1353
To be overridden
1354
"""
1355
if self.plugin:
1356
if not hasattr(ids, '__iter__'):
1357
self.plugin.exec_events_ids(EVTGETITEM, [ids])
1358
else:
1359
self.plugin.exec_events_ids(EVTGETITEM, ids)
1360
1361
del self[ids]
1362
self._is_modified = True
1363
1364
def format_value(self, _id, show_unit=False, show_parentesis=False):
1365
if show_unit:
1366
unit = ' '+self.format_unit(show_parentesis)
1367
else:
1368
unit = ''
1369
# return repr(self[_id])+unit
1370
1371
#self.min = minval
1372
#self.max = maxval
1373
#self.digits_integer = digits_integer
1374
#self.digits_fraction = digits_fraction
1375
val = self[_id]
1376
tt = type(val)
1377
1378
if tt in (types.LongType, types.IntType):
1379
return str(val)+unit
1380
1381
elif tt in (types.FloatType, types.ComplexType):
1382
if hasattr(attrconf, 'digits_fraction'):
1383
digits_fraction = self.digits_fraction
1384
else:
1385
digits_fraction = 3
1386
return "%."+str(digits_fraction)+"f" % (val)+unit
1387
1388
else:
1389
return str(val)+unit
1390
1391
# return str(self[_id])+unit
1392
1393
def format(self, ids=None):
1394
# TODO: incredibly slow when calling format_value for each value
1395
text = ''
1396
1397
if ids is None:
1398
ids = self._manager.get_ids()
1399
if not hasattr(ids, '__iter__'):
1400
ids = [ids]
1401
1402
#unit = self.format_unit()
1403
attrname = self.attrname
1404
for id in ids:
1405
text += '%s[%d] = %s\n' % (attrname, id, self.format_value(id, show_unit=True))
1406
1407
return text[:-1] # remove last newline
1408
1409
1410
class NumcolConf(ColConf):
1411
def __init__(self, attrname, default,
1412
digits_integer=None, digits_fraction=None,
1413
minval=None, maxval=None,
1414
**attrs):
1415
self.min = minval
1416
self.max = maxval
1417
self.digits_integer = digits_integer
1418
self.digits_fraction = digits_fraction
1419
1420
ColConf.__init__(self, attrname, default, **attrs)
1421
1422
1423
class IdsConf(ColConf):
1424
"""
1425
Column, where each entry is the id of a single Table.
1426
"""
1427
1428
def __init__(self, attrname, tab, id_default=-1, is_index=False, perm='r', **kwargs):
1429
self._is_index = is_index
1430
self._tab = tab
1431
1432
AttrConf.__init__(self, attrname,
1433
id_default, # default id
1434
struct='odict',
1435
metatype='id',
1436
perm=perm,
1437
**kwargs
1438
)
1439
self.init_xml()
1440
# print 'IdsConf.__init__',attrname
1441
# print ' ',self._tab.xmltag,self._attrconfig_id_tab
1442
1443
def set_linktab(self, tab):
1444
self._tab = tab
1445
1446
def get_linktab(self):
1447
return self._tab
1448
1449
def init_xml(self):
1450
# print 'init_xml',self.attrname
1451
if self._tab.xmltag is not None:
1452
1453
# necessary?? see ObjMan.write_xml
1454
xmltag_tab, xmltag_item_tab, attrname_id_tab = self._tab.xmltag
1455
if (attrname_id_tab is None) | (attrname_id_tab is ''):
1456
self._attrconfig_id_tab = None
1457
else:
1458
self._attrconfig_id_tab = getattr(self._tab, attrname_id_tab) # tab = tabman !
1459
1460
if not hasattr(self, 'is_xml_include_tab'):
1461
# this means that entire table rows will be included
1462
self.is_xml_include_tab = False
1463
# print ' xmltag_tab, xmltag_item_tab, attrname_id_tab',xmltag_tab, xmltag_item_tab, attrname_id_tab,self.is_xml_include_tab
1464
1465
else:
1466
self._attrconfig_id_tab = None
1467
self.is_xml_include_tab = False
1468
1469
def write_xml(self, fd, _id, indent=0):
1470
if (self.xmltag is not None) & (self[_id] >= 0):
1471
if self._attrconfig_id_tab is None:
1472
self._write_xml_value(self[_id], fd)
1473
elif self.is_xml_include_tab:
1474
# this means that entire table rows will be included
1475
self._tab.write_xml(fd, indent, ids=self[_id], is_print_begin_end=False)
1476
else:
1477
self._write_xml_value(self._attrconfig_id_tab[self[_id]], fd)
1478
1479
def _write_xml_value(self, val, fd):
1480
# print 'write_xml',self.xmltag,hasattr(val, '__iter__')
1481
if hasattr(val, '__iter__'):
1482
if len(val) > 0:
1483
if hasattr(val[0], '__iter__'):
1484
# matrix
1485
fd.write(xm.mat(self.xmltag, val))
1486
else:
1487
# list
1488
fd.write(xm.arr(self.xmltag, val, self.xmlsep))
1489
else:
1490
# empty list
1491
# fd.write(xm.arr(self.xmltag,val))
1492
# don't even write empty lists
1493
pass
1494
1495
elif type(self._default) in (types.UnicodeType, types.StringType):
1496
if len(val) > 0:
1497
fd.write(xm.num(self.xmltag, val))
1498
1499
else:
1500
# scalar number or string
1501
fd.write(xm.num(self.xmltag, val))
1502
1503
def get_defaults(self, ids):
1504
# create a list, should work for all types and dimensions
1505
# default can be scalar or an array of any dimension
1506
# print '\n\nget_defaults',self.attrname,ids,self.get_default()
1507
return len(ids)*[self.get_default()]
1508
1509
def _getstate_specific(self, state):
1510
"""
1511
Called by __getstate__ to add/change specific states,
1512
before returning states.
1513
To be overridden.
1514
"""
1515
if self._is_save:
1516
# if self._is_child:
1517
# # OK self.value already set in
1518
# pass
1519
# else:
1520
# # remove table reference and create ident
1521
# print '_getstate_specific',self._tab.get_ident_abs()
1522
state['_tab'] = None
1523
state['_ident_tab'] = self._tab.get_ident_abs()
1524
1525
def init_postload_internal(self, man, obj):
1526
# print 'IdsConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'obj:',obj.ident
1527
1528
AttrConf.init_postload_internal(self, man, obj)
1529
# if self._is_child:
1530
# print ' make sure children get initialized'
1531
# print ' call init_postload_internal of',self._tab.ident
1532
# self._tab.init_postload_internal(obj)
1533
1534
def init_postload_external(self):
1535
# if self._is_child:
1536
# # restore normally
1537
# AttrConf.init_postload_external(self)
1538
# self._tab.init_postload_external()
1539
# else:
1540
1541
# Substitute absolute ident with link object.
1542
# Called from init_postload_external of attrsman during load_obj
1543
#
1544
ident_abs = self._ident_tab
1545
# print 'reset_linkobj',self.attrname,ident_abs
1546
obj = self.get_obj()
1547
rootobj = obj.get_root()
1548
# print ' rootobj',rootobj.ident
1549
linkobj = rootobj.get_obj_from_ident(ident_abs)
1550
# print ' linkobj',linkobj.ident
1551
self._tab = linkobj
1552
self.init_xml()
1553
1554
def is_modified(self):
1555
return False
1556
1557
1558
class TabIdsConf(ColConf):
1559
"""
1560
Column, where each entry contains a tuple with table object and id.
1561
"""
1562
1563
def __init__(self, attrname, is_index=False, **kwargs):
1564
self._is_index = is_index
1565
AttrConf.__init__(self, attrname,
1566
-1, # default id
1567
struct='odict',
1568
metatype='tabids',
1569
**kwargs
1570
)
1571
1572
def get_defaults(self, ids):
1573
# create a list, should work for all types and dimensions
1574
# default can be scalar or an array of any dimension
1575
# print '\n\nget_defaults',self.attrname,ids,self.get_default()
1576
return len(ids)*[(None, -1)]
1577
1578
def reset(self):
1579
# TODO: this will reset all the tables
1580
# instead should reset only the specified ids
1581
if self._is_child:
1582
for tab, ids in self.get_value():
1583
tab.reset()
1584
1585
def clear(self):
1586
self.reset()
1587
# necessary? because tbles have been cleared from manager
1588
# if self._is_child:
1589
# for tab, ids in self.get_value():
1590
# tab.clear()
1591
1592
def _getstate_specific(self, state):
1593
"""
1594
Called by __getstate__ to add/change specific states,
1595
before returning states.
1596
To be overridden.
1597
"""
1598
if self._is_save:
1599
n = len(state['value'])
1600
state['value'] = None
1601
_tabids_save = n*[None]
1602
i = 0
1603
for tab, ids in self.get_value():
1604
_tabids_save[i] = [tab.get_ident_abs(), ids]
1605
i += 1
1606
state['_tabids_save'] = _tabids_save
1607
1608
def init_postload_internal(self, man, obj):
1609
# print 'IdsConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'obj:',obj.ident
1610
1611
AttrConf.init_postload_internal(self, man, obj)
1612
# if self._is_child:
1613
# print ' make sure children get initialized'
1614
# print ' call init_postload_internal of',self._tab.ident
1615
# self._tab.init_postload_internal(obj)
1616
1617
def init_postload_external(self):
1618
# if self._is_child:
1619
# # restore normally
1620
# AttrConf.init_postload_external(self)
1621
# self._tab.init_postload_external()
1622
# else:
1623
1624
# Substitute absolute ident with link object.
1625
# Called from init_postload_external of attrsman during load_obj
1626
#
1627
#ident_abs = self._ident_tab
1628
# print 'reset_linkobj',self.attrname,ident_abs
1629
#obj = self.get_obj()
1630
#rootobj = obj.get_root()
1631
# print ' rootobj',rootobj.ident
1632
#linkobj = rootobj.get_obj_from_ident(ident_abs)
1633
# print ' linkobj',linkobj.ident
1634
#self._tab = linkobj
1635
1636
# Substitute absolute ident with link object.
1637
# Called from init_postload_external of attrsman during load_obj
1638
#
1639
_tabids_save = self._tabids_save
1640
#ident_abs = self._ident_value
1641
# print 'init_postload_external',self.attrname,_tabids_save
1642
obj = self.get_obj()
1643
rootobj = obj.get_root()
1644
# print ' rootobj',rootobj.ident
1645
tabids = len(self._tabids_save)*[None]
1646
i = 0
1647
for tabident, ids in self._tabids_save:
1648
tab = rootobj.get_obj_from_ident(tabident)
1649
# print ' ',tab.get_ident_abs(), ids
1650
tabids[i] = [tab, ids]
1651
i += 1
1652
1653
self.set_value(tabids)
1654
1655
def is_modified(self):
1656
return False
1657
1658
1659
class ObjsConf(ColConf):
1660
"""
1661
Column, where each entry is an object of class objclass with
1662
ident= (attrname, id).
1663
"""
1664
# TODO:
1665
# there is a problems with objects that are stored here
1666
# in particular if objects are Table. What is their correct ident
1667
# or absolute ident. Currently it is not correct.
1668
# This leads to incorrect referencing when linked from elsewhere
1669
# for example within TabIdListArrayConf
1670
# .get_ident_abs() needs to to be correct, such that
1671
# get_obj_from_ident can locate them
1672
# maybe it is not an issue of ObjsConf itself,
1673
# but the Objects stored must have a special getident method
1674
1675
def __init__(self, attrname, is_index=False, **kwargs):
1676
self._is_index = is_index
1677
self._is_child = True # at the moment no links possible
1678
AttrConf.__init__(self, attrname,
1679
None, # BaseObjman('empty'), # default id
1680
struct='odict',
1681
metatype='obj',
1682
perm='r',
1683
**kwargs
1684
)
1685
1686
def set_obj(self, obj):
1687
"""
1688
Method to set instance of managed object.
1689
Used by add method of AttrManager
1690
"""
1691
# print 'set_obj',self.attrname,obj.ident
1692
AttrConf.set_obj(self, obj)
1693
1694
# if self._is_child:
1695
obj.set_child(self)
1696
1697
# def get_valueobj(self, id = None):
1698
# """
1699
# This is called by get_childobj to retrive the child instance.
1700
# Here this is just the table.
1701
# """
1702
# return self._tab
1703
1704
def predelete(self):
1705
AttrConf.predelete(self)
1706
# if self._is_child:
1707
self.get_obj().del_child(self.attrname)
1708
1709
# def _getstate_specific(self, state):
1710
# """
1711
# Called by __getstate__ to add/change specific states,
1712
# before returning states.
1713
# To be overridden.
1714
# """
1715
# if self._is_save:
1716
# if self._is_child:
1717
# # OK self.value already set in
1718
# pass
1719
# else:
1720
# # remove column reference and create column with idents
1721
# state['value']= None
1722
# idents_obj = OrderedDict()
1723
# linkobjs = self.get_value()
1724
# for _id in self.get_ids():
1725
# idents_obj[_id] = linkobjs[_id].get_ident_abs()
1726
# state['_idents_obj'] = idents_obj
1727
1728
def init_postload_internal(self, man, obj):
1729
# print 'ObjsConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'obj:',obj.ident
1730
1731
AttrConf.init_postload_internal(self, man, obj)
1732
# if self._is_child:
1733
1734
# make sure all children in column get initialized
1735
# print ' make sure childrenS get initialized'
1736
childobjs = self.get_value()
1737
1738
obj = self.get_obj()
1739
# print 'init_postload_internal',self.attrname,obj,obj.ident
1740
for _id in obj.get_ids():
1741
# print ' call init_postload_internal of',childobjs[_id].ident
1742
childobjs[_id].init_postload_internal(obj) # attention obj is the parent object!
1743
1744
def reset(self):
1745
# print 'ObjsConf.reset',self.get_value(),len(self.get_obj().get_ids())
1746
#obj = self.get_obj()
1747
# print 'init_postload_internal',self.attrname,obj,obj.ident
1748
childobjs = self.get_value()
1749
for _id in self.get_obj().get_ids():
1750
# print ' call reset of',childobjs[_id].ident,_id
1751
childobjs[_id].reset()
1752
1753
def clear(self):
1754
odict = self.get_init()
1755
if not self._is_localvalue:
1756
setattr(self._obj, self.attrname, odict)
1757
if self._is_index:
1758
self.reset_index()
1759
1760
def is_modified(self):
1761
# if self._is_child
1762
#is_modified = self.get_value().is_modified()
1763
# print 'is_modified', self.attrname, is_modified
1764
1765
childobjs = self.get_value()
1766
1767
#obj = self.get_obj()
1768
# print 'init_postload_internal',self.attrname,obj,obj.ident
1769
for _id in self.get_obj().get_ids():
1770
# print ' call init_postload_internal of',childobjs[_id].ident
1771
if childobjs[_id].is_modified():
1772
return True
1773
1774
def set_modified(self, is_modified):
1775
childobjs = self.get_value()
1776
1777
obj = self.get_obj()
1778
# print 'init_postload_internal',self.attrname,obj,obj.ident
1779
for _id in self.get_obj().get_ids():
1780
# print ' call init_postload_internal of',childobjs[_id].ident
1781
childobjs[_id].set_modified(is_modified)
1782
1783
def init_postload_external(self):
1784
# if self._is_child:
1785
# restore normally
1786
AttrConf.init_postload_external(self)
1787
childobjs = self.get_value()
1788
1789
for _id in self.get_obj().get_ids():
1790
childobjs[_id].init_postload_external()
1791
1792
# def get_name(self):
1793
# return self.'Table ID for '+self._tab.get_name()
1794
#
1795
# def get_info(self):
1796
# return 'ID for Table:\n'+self._tab.get_info()
1797
1798
1799
class Attrsman:
1800
"""
1801
Manages all attributes of an object
1802
1803
if argument obj is specified with an instance
1804
then attributes are stored under this instance.
1805
The values of attrname is then directly accessible with
1806
1807
obj.attrname
1808
1809
If nothing is specified, then column attribute will be stored under
1810
the respective config instance of this attrsman (self).
1811
The values of attrname is then directly accessible with
1812
1813
self.attrname.value
1814
"""
1815
1816
def __init__(self, obj, attrname='attrsman', is_plugin=False):
1817
1818
if obj is None:
1819
# this means that column data will be stored
1820
# in value attribute of attrconfigs
1821
obj = self
1822
self._is_localvalue = True
1823
else:
1824
# this means that column data will be stored under obj
1825
self._is_localvalue = False
1826
1827
self._obj = obj # managed object
1828
self._attrconfigs = [] # managed attribute config instances
1829
self.attrname = attrname # the manager's attribute name in the obj instance
1830
1831
self._attrs_nosave = set(ATTRS_NOSAVE)
1832
1833
# groupes of attributes
1834
# key=groupname, value = list of attribute config instances
1835
self._groups = {}
1836
1837
self.init_plugin(is_plugin)
1838
1839
def init_plugin(self, is_plugin):
1840
if is_plugin:
1841
self.plugin = Plugin(self)
1842
else:
1843
self.plugin = None
1844
1845
def enable_plugin(self, is_enabled=True):
1846
if self.plugin is not None:
1847
self.plugin.enable(is_enabled)
1848
1849
def is_localvalue(self):
1850
return self._is_localvalue
1851
1852
def has_attrname(self, attrname):
1853
# attention this is a trick, exploiting the fact that the
1854
# attribute object with all the attr info is an attribute
1855
# of the attr manager (=self)
1856
return hasattr(self, attrname)
1857
1858
def is_modified(self):
1859
for attrconf in self._attrconfigs:
1860
# TODO: not very clean
1861
if hasattr(attrconf, 'is_child'):
1862
if attrconf.is_child():
1863
if attrconf.is_modified():
1864
return True
1865
else:
1866
if attrconf.is_modified():
1867
return True
1868
1869
return False
1870
1871
def set_modified(self, is_modified=True):
1872
for attrconf in self._attrconfigs:
1873
attrconf.set_modified(is_modified)
1874
1875
def get_modified(self):
1876
# returns a list of modified attributes
1877
modified = []
1878
for attrconf in self._attrconfigs:
1879
if attrconf.is_modified():
1880
modified.append(attrconf)
1881
return modified
1882
1883
def __getitem__(self, attrname):
1884
return getattr(self, attrname).get_value()
1885
1886
def get_config(self, attrname):
1887
return getattr(self, attrname) # a bit risky
1888
1889
def get_configs(self, is_all=False, structs=None, filtergroupnames=None, is_private=False):
1890
# print 'get_configs',self,self._obj.ident,structs,filtergroupnames,len(self._attrconfigs)
1891
if is_all:
1892
return self._attrconfigs
1893
else:
1894
attrconfigs = []
1895
for attrconf in self._attrconfigs:
1896
# print ' found',attrconf.attrname,attrconf.struct,'groupnames',attrconf.groupnames
1897
is_check = True
1898
if (structs is not None):
1899
if (attrconf.struct not in structs):
1900
is_check = False
1901
1902
if is_check:
1903
# print ' **is_check',is_check
1904
if len(attrconf.groupnames) > 0:
1905
if ('_private' not in attrconf.groupnames) | is_private:
1906
# print ' not private'
1907
if filtergroupnames is not None:
1908
# print ' apply filtergroupnames',filtergroupnames,attrconf.groupnames
1909
if not set(filtergroupnames).isdisjoint(attrconf.groupnames):
1910
# print ' append',attrconf.attrname
1911
attrconfigs.append(attrconf)
1912
else:
1913
# print ' no filtergroupnames'
1914
attrconfigs.append(attrconf)
1915
else:
1916
if filtergroupnames is None:
1917
attrconfigs.append(attrconf)
1918
1919
return attrconfigs
1920
1921
# def get_colconfigs(self, is_all = False):
1922
# return []
1923
1924
def get_obj(self):
1925
return self._obj
1926
1927
def add(self, attrconf, is_overwrite=False, is_prepend=False):
1928
"""
1929
Add a one or several new attributes to be managed.
1930
kwargs has attribute name as key and Attribute configuration object
1931
as value.
1932
"""
1933
1934
attrname = attrconf.attrname
1935
# print '\n\nAttrsman.add',self.get_obj().ident,'add',attrname,self.has_attrname(attrname)
1936
# dir(self._obj)
1937
if (not self.has_attrname(attrname)) | is_overwrite:
1938
attrconf.set_obj(self._obj)
1939
attrconf.set_manager(self)
1940
1941
# set configuration object as attribute of AttrManager
1942
setattr(self, attrname, attrconf)
1943
1944
# append also to the list of managed objects
1945
if is_prepend:
1946
self._attrconfigs.insert(0, attrconf)
1947
else:
1948
self._attrconfigs.append(attrconf)
1949
1950
# insert in groups
1951
self.insert_groupnames(attrconf)
1952
1953
if self.plugin:
1954
self.plugin.exec_events_attr(EVTADD, attrconf)
1955
1956
# return default value as attribute of managed object
1957
if (attrconf.struct in STRUCTS_SCALAR) & (attrconf.is_returnval()): # == 'scalar':
1958
return attrconf.get_init()
1959
else:
1960
return None # table configs do their own init
1961
1962
else:
1963
# print ' attribute with this name already exists',attrname,type(attrconf)
1964
# TODO: here we could do some intelligent updating
1965
del attrconf
1966
attrconf = getattr(self, attrname)
1967
# print ' existing',attrconf,type(attrconf)
1968
if (attrconf.struct in STRUCTS_SCALAR) & (attrconf.is_returnval()): # == 'scalar':
1969
return attrconf.get_value()
1970
else:
1971
return None # table configs do their own init
1972
1973
def do_not_save_attr(self, attrname):
1974
self._attrs_nosave.add(attrname)
1975
1976
def do_save_attr(self, attrname):
1977
if attrname in self._attrs_nosave:
1978
self._attrs_nosave.remove(attrname)
1979
1980
def do_not_save_attrs(self, attrnames):
1981
self._attrs_nosave.update(attrnames)
1982
1983
def insert_groupnames(self, attrconf):
1984
if len(attrconf.groupnames) > 0:
1985
for groupname in attrconf.groupnames:
1986
1987
if not self._groups.has_key(groupname):
1988
self._groups[groupname] = []
1989
1990
if attrconf not in self._groups[groupname]:
1991
self._groups[groupname].append(attrconf)
1992
1993
def del_groupname(self, attrconf):
1994
if len(attrconf.groupnames) > 0:
1995
for groupname in self._groups.keys():
1996
attrconfigs = self._groups[groupname]
1997
if attrconf in attrconfigs:
1998
if groupname not in attrconf.groupnames:
1999
attrconfigs.remove(attrconf)
2000
2001
def get_groups(self):
2002
return self._groups
2003
2004
def get_groupnames(self):
2005
return self._groups.keys()
2006
2007
def has_group(self, groupname):
2008
return self._groups.has_key(groupname)
2009
2010
def get_group(self, name):
2011
"""
2012
Returns a list with attributes that belong to that group name.
2013
"""
2014
# print 'get_group self._groups=\n',self._groups.keys()
2015
return self._groups.get(name, [])
2016
2017
def get_group_attrs(self, name):
2018
"""
2019
Returns a dictionary with all attributes of a group.
2020
Key is attribute name and value is attribute value.
2021
"""
2022
# print 'get_group_attrs', self._groups
2023
attrs = OrderedDict()
2024
if not self._groups.has_key(name):
2025
return attrs
2026
for attrconf in self._groups[name]:
2027
# print ' attrconf.attrname',attrconf.attrname
2028
attrs[attrconf.attrname] = getattr(self._obj, attrconf.attrname)
2029
# print ' attrs',attrs
2030
return attrs
2031
2032
def write_csv(self, fd, sep=',',
2033
show_parentesis=False, attrconfigs=None,
2034
groupnames=None,
2035
is_export_not_save=True):
2036
# print 'Attrsman.write_csv attrconfigs'#,attrconfigs,'groupnames',groupnames,
2037
if attrconfigs is None:
2038
attrconfigs = self.get_configs(is_all=False, structs=STRUCTS_SCALAR, filtergroupnames=groupnames)
2039
2040
for attrconf in attrconfigs:
2041
# print ' attrconfig', attrconf.attrname,attrconf.struct,attrconf.metatype
2042
if (attrconf.is_save() | is_export_not_save) & (attrconf.struct in STRUCTS_SCALAR):
2043
mt = attrconf.metatype
2044
2045
if mt == 'id':
2046
fd.write('%s %s%s%s\n' % (attrconf.attrname, attrconf.format_unit(show_parentesis),
2047
sep, attrconf.get_linktab().format_ids([attrconf.get_value()])))
2048
else:
2049
fd.write('%s %s%s%s\n' % (attrconf.attrname, attrconf.format_unit(
2050
show_parentesis), sep, attrconf.format_value()))
2051
2052
def print_attrs(self, show_unit=True, show_parentesis=False, attrconfigs=None):
2053
print 'Attributes of', self._obj._name, 'ident_abs=', self._obj.get_ident_abs()
2054
if attrconfigs is None:
2055
attrconfigs = self.get_configs(structs=STRUCTS_SCALAR)
2056
2057
# for attrconf in attrconfigs:
2058
# print ' %s =\t %s'%(attrconf.attrname, attrconf.format_value(show_unit=True))
2059
2060
def save_values(self, state):
2061
"""
2062
Called by the managed object during save to save the
2063
attribute values.
2064
"""
2065
for attrconfig in self.get_configs():
2066
attrconfig.save_value(state)
2067
2068
def delete(self, attrname):
2069
"""
2070
Delete attribute with respective name
2071
"""
2072
# print '.__delitem__','attrname=',attrname
2073
2074
# if hasattr(self,attrname):
2075
attrconf = getattr(self, attrname)
2076
2077
if attrconf in self._attrconfigs:
2078
if self.plugin:
2079
self.plugin.exec_events_attr(EVTDEL, attrconf)
2080
2081
for groupname in attrconf.groupnames:
2082
self._groups[groupname].remove(attrconf)
2083
2084
self._attrconfigs.remove(attrconf)
2085
attrconf.predelete() # this will remove also the value attribute
2086
2087
#attrname = attrconf.attrname
2088
del self.__dict__[attrname] # delete config
2089
return True
2090
2091
return False # attribute not managed
2092
# return False # attribute not existant
2093
2094
def __getstate__(self):
2095
# if hasattr(self,'attrname'):
2096
# print 'Attrsman.__getstate__ of',self.attrname,' of obj=',self._obj.ident,'id',id(self),'id obj',id(self._obj)
2097
#
2098
# else:
2099
# print 'WARNING in Attrsman.__getstate__',self,'attrname missing','id',id(self),'id obj',id(self._obj)
2100
2101
if not hasattr(self, '_obj'):
2102
print 'WARNING: unknown obj in attrman', self, type(self)
2103
# print ' dir',dir(self)
2104
# if hasattr(self,'attrname'):
2105
# print ' No attrman but attribute',self.attrname
2106
# for attrconf in self.get_configs(is_all=True):
2107
# print ' attrname=',attrconf.attrname
2108
return {}
2109
2110
# if not hasattr(self,'_attrs_nosave'):
2111
# print 'WARNING: in __getstate__ of',self.attrname#,'obj',self._obj,'has no attr _attrs_nosave'
2112
# #self.print_attrs()
2113
# print 'dict=\n',self.__dict__
2114
2115
# print ' self.__dict__=\n',self.__dict__.keys()
2116
2117
state = {}
2118
for attr in self.__dict__.keys():
2119
# print ' attr',attr,self.__dict__[attr]
2120
# TODO: optimize and put this at the end
2121
if attr == 'plugin':
2122
plugin = self.__dict__[attr]
2123
if plugin is not None:
2124
state[attr] = True
2125
else:
2126
state[attr] = False
2127
2128
elif attr == '_attrconfigs':
2129
attrconfigs_save = []
2130
for attrconfig in self._attrconfigs:
2131
2132
if attrconfig.is_save():
2133
# print ' save',attrconfig.attrname
2134
# if attrconfig.struct == 'array':
2135
# print ' size =',len(self)
2136
attrconfigs_save.append(attrconfig)
2137
state[attr] = attrconfigs_save
2138
2139
elif attr not in self._attrs_nosave:
2140
state[attr] = self.__dict__[attr]
2141
2142
# print ' _attrs_nosave=', self._attrs_nosave
2143
# print ' state=', state
2144
return state
2145
2146
def __setstate__(self, state):
2147
# print '__setstate__',self
2148
2149
# this is always required, but will not be saved
2150
# self.plugins={}
2151
2152
for attr in state.keys():
2153
# print ' set state',attr
2154
# plugin set in init_postload_internal
2155
# if attr=='plugin':
2156
# if state[attr]==True:
2157
# self.__dict__[attr] = Plugin(self)
2158
# else:
2159
# self.__dict__[attr]= None
2160
# else:
2161
self.__dict__[attr] = state[attr]
2162
2163
def init_postload_internal(self, obj):
2164
"""
2165
Called after set state.
2166
Link internal states.
2167
"""
2168
# print 'Attrsman.init_postload_internal of obj:',obj.ident
2169
2170
if not hasattr(self, '_attrs_nosave'):
2171
self._attrs_nosave = set(ATTRS_NOSAVE)
2172
2173
# if not hasattr(self,'_attrs_nosave'):
2174
# print 'WARNING: in init_postload_internal of',self.attrname,'obj',obj,'has no attr _attrs_nosave'
2175
2176
self._obj = obj
2177
self.init_plugin(self.plugin)
2178
for attrconfig in self.get_configs(is_all=True):
2179
# print ' call init_postload_internal of',attrconfig.attrname
2180
attrconfig.init_postload_internal(self, obj)
2181
2182
def init_postload_external(self):
2183
"""
2184
Called after set state.
2185
Link external states.
2186
"""
2187
# print 'Attrsman.init_postload_external',self._obj.get_ident()
2188
2189
for attrconfig in self.get_configs(is_all=True):
2190
# print ' call',attrconfig.attrname,attrconfig.metatype
2191
attrconfig.init_postload_external()
2192
2193
2194
class Tabman(Attrsman):
2195
"""
2196
Manages all table attributes of an object.
2197
2198
if argument obj is specified with an instance
2199
then column attributes are stored under this instance.
2200
The values of attrname is then directly accessible with
2201
2202
obj.attrname
2203
2204
If nothing is specified, then column attribute will be stored under
2205
the respective config instance of this tab man (self).
2206
The values of attrname is then directly accessible with
2207
2208
self.attrname.value
2209
2210
"""
2211
2212
def __init__(self, obj=None, **kwargs):
2213
Attrsman.__init__(self, obj, **kwargs)
2214
self._colconfigs = []
2215
self._ids = []
2216
2217
def add_col(self, attrconf):
2218
# print 'add_col',attrconf.attrname,attrconf.is_index()
2219
attrname = attrconf.attrname
2220
if not self.has_attrname(attrname):
2221
Attrsman.add(self, attrconf) # insert in common attrs database
2222
self._colconfigs.append(attrconf)
2223
# returns initial array and also create local array if self._is_localvalue == True
2224
return attrconf.get_init()
2225
else:
2226
return getattr(self, attrname).get_value()
2227
2228
def delete(self, attrname):
2229
"""
2230
Delete attribute with respective name
2231
"""
2232
# print '.__delitem__','attrname=',attrname
2233
2234
if hasattr(self, attrname):
2235
attrconf = getattr(self, attrname)
2236
if self.plugin:
2237
self.plugin.exec_events_attr(EVTDEL, attrconf)
2238
if Attrsman.delete(self, attrname):
2239
if attrconf in self._colconfigs:
2240
self._colconfigs.remove(attrconf)
2241
2242
def get_colconfigs(self, is_all=False, filtergroupnames=None):
2243
if is_all:
2244
return self._colconfigs
2245
else:
2246
colconfigs = []
2247
if filtergroupnames is not None:
2248
filtergroupnameset = set(filtergroupnames)
2249
for colconfig in self._colconfigs:
2250
if len(colconfig.groupnames) > 0:
2251
if '_private' not in colconfig.groupnames:
2252
if filtergroupnames is not None:
2253
if not filtergroupnameset.isdisjoint(colconfig.groupnames):
2254
colconfigs.append(colconfig)
2255
else:
2256
colconfigs.append(colconfig)
2257
2258
else:
2259
if filtergroupnames is None:
2260
colconfigs.append(colconfig)
2261
2262
return colconfigs
2263
2264
def get_ids(self):
2265
return self._ids
2266
2267
def __len__(self):
2268
"""
2269
Determine current array length (same for all arrays)
2270
"""
2271
2272
return len(self._ids)
2273
2274
def __contains__(self, _id):
2275
return _id in self._ids
2276
2277
def select_ids(self, mask):
2278
2279
ids_mask = []
2280
i = 0
2281
for _id in self.get_ids():
2282
if mask[i]:
2283
ids_mask.append(_id)
2284
i += 1
2285
2286
return ids_mask
2287
2288
def suggest_id(self, is_zeroid=False):
2289
"""
2290
Returns a an availlable id.
2291
2292
Options:
2293
is_zeroid=True allows id to be zero.
2294
2295
"""
2296
if is_zeroid:
2297
id0 = 0
2298
else:
2299
id0 = 1
2300
2301
id_set = set(self.get_ids())
2302
if len(id_set) == 0:
2303
id_max = 0
2304
else:
2305
id_max = max(id_set)
2306
# print 'suggest_id',id0,
2307
return list(id_set.symmetric_difference(xrange(id0, id_max+id0+1)))[0]
2308
2309
def suggest_ids(self, n, is_zeroid=False):
2310
"""
2311
Returns a list of n availlable ids.
2312
It returns even a list for n=1.
2313
2314
Options:
2315
is_zeroid=True allows id to be zero.
2316
"""
2317
if is_zeroid:
2318
id0 = 0
2319
else:
2320
id0 = 1
2321
id_set = set(self.get_ids())
2322
if len(id_set) == 0:
2323
id_max = 0
2324
else:
2325
id_max = max(id_set)
2326
2327
return list(id_set.symmetric_difference(xrange(id0, id_max+id0+n)))[:n]
2328
2329
def add_rows(self, n=None, ids=[], **attrs):
2330
if n is not None:
2331
ids = self.suggest_ids(n)
2332
elif len(ids) == 0:
2333
# get number of rows from any valye vector provided
2334
ids = self.suggest_ids(len(attrs.values()[0]))
2335
else:
2336
# ids already given , no ids to create
2337
pass
2338
2339
self._ids += ids
2340
# print 'add_rows ids', ids
2341
for colconfig in self._colconfigs:
2342
colconfig.add(ids, values=attrs.get(colconfig.attrname, None))
2343
if self.plugin:
2344
self.plugin.exec_events_ids(EVTADDITEM, ids)
2345
return ids
2346
2347
def add_row(self, _id=None, **attrs):
2348
if _id is None:
2349
_id = self.suggest_id()
2350
self._ids += [_id, ]
2351
for colconfig in self._colconfigs:
2352
colconfig.add(_id, values=attrs.get(colconfig.attrname, None))
2353
if self.plugin:
2354
self.plugin.exec_events_ids(EVTADDITEM, [_id])
2355
return _id
2356
2357
def set_row(self, _id, **attrs):
2358
for colconfig in self._colconfigs:
2359
colconfig.set(_id, values=attrs.get(colconfig.attrname, None))
2360
if self.plugin:
2361
self.plugin.exec_events_ids(EVTSETITEM, [_id])
2362
2363
def set_rows(self, ids, **attrs):
2364
2365
# print 'add_rows ids', ids
2366
for colconfig in self._colconfigs:
2367
colconfig.set(ids, values=attrs.get(colconfig.attrname, None))
2368
if self.plugin:
2369
self.plugin.exec_events_ids(SETSETITEM, ids)
2370
2371
def get_row(self, _id):
2372
attrvalues = {}
2373
if self.plugin:
2374
self.plugin.exec_events_ids(EVTGETITEM, [_id])
2375
for attrconfig in self._colconfigs:
2376
attrvalues[attrconfig.attrname] = attrconfig[_id]
2377
2378
return attrvalues
2379
2380
def del_rows(self, ids):
2381
if self.plugin:
2382
self.plugin.exec_events_ids(EVTDELITEM, ids)
2383
for colconfig in self._colconfigs:
2384
del colconfig[ids]
2385
2386
for _id in ids:
2387
self._ids.remove(_id)
2388
2389
def del_row(self, _id):
2390
if self.plugin:
2391
self.plugin.exec_events_ids(EVTDELITEM, [_id])
2392
for colconfig in self._colconfigs:
2393
del colconfig[_id]
2394
self._ids.remove(_id)
2395
2396
def __delitem__(self, ids):
2397
"""
2398
remove rows correspondent to the given ids from all array and dict
2399
attributes
2400
"""
2401
if hasattr(ids, '__iter__'):
2402
self.del_rows(ids)
2403
else:
2404
self.del_row(ids)
2405
2406
def print_attrs(self, ids=None, **kwargs):
2407
# print 'Attributes of',self._obj._name,'(ident=%s)'%self._obj.ident
2408
Attrsman.print_attrs(self, attrconfigs=self.get_configs(structs=['scalar']), **kwargs)
2409
# print ' ids=',self._ids
2410
if ids is None:
2411
ids = self.get_ids()
2412
2413
for _id in ids:
2414
for attrconf in self.get_configs(structs=STRUCTS_COL):
2415
print ' %s[%d] =\t %s' % (attrconf.attrname, _id, attrconf.format_value(_id, show_unit=True))
2416
2417
def write_csv(self, fd, sep=',', ids=None,
2418
attrconfigs=None,
2419
groupnames=None,
2420
show_parentesis=True,
2421
is_export_not_save=True, # export attr, also non save
2422
name_id='ID',
2423
):
2424
# if attrconfigs is None:
2425
# attrconfigs = self.get_configs()
2426
# print 'Tabman.write_csv attrconfigs is_export_not_save',is_export_not_save
2427
2428
Attrsman.write_csv(self, fd, sep=sep,
2429
show_parentesis=show_parentesis,
2430
groupnames=groupnames,
2431
attrconfigs=attrconfigs,
2432
#is_export_private = False,
2433
is_export_not_save=is_export_not_save, # export attr, also non save
2434
)
2435
# fd.write('\n')
2436
# for attrconf in attrconfigs:
2437
# #print ' %s =\t %s'%(attrconf.attrname, attrconf.format_value(show_unit=True))
2438
# fd.write( '%s %s%s%s\n'%(attrconf.attrname,format_unit(show_parentesis), sep, attrconf.format_value()))
2439
2440
if ids is None:
2441
ids = self.get_ids()
2442
2443
if groupnames is not None:
2444
#attrconfigs = self.get_group(groupname)
2445
attrconfigs = self.get_configs(is_all=False, filtergroupnames=groupnames)
2446
is_exportall = False
2447
2448
elif attrconfigs is None:
2449
attrconfigs = self.get_colconfigs(is_all=False)
2450
#is_exportall = False
2451
2452
# check if attributes are all column attribute and indicted for save
2453
attrconfigs_checked = []
2454
for attrconf in attrconfigs:
2455
if (attrconf.is_save() | is_export_not_save) & (attrconf.struct in STRUCTS_COL):
2456
2457
attrconfigs_checked.append(attrconf)
2458
2459
# first table row
2460
row = name_id
2461
for attrconf in attrconfigs_checked:
2462
# print ' attrconfig', attrconf.attrname,attrconf.metatype
2463
row += sep+self._clean_csv(attrconf.format_symbol(show_parentesis=show_parentesis), sep)
2464
fd.write(row+'\n')
2465
2466
# rest
2467
for _id in ids:
2468
row = str(_id)
2469
row = self._clean_csv(row, sep)
2470
for attrconf in attrconfigs:
2471
mt = attrconf.metatype
2472
# print ' attrconf,',attrconf.attrname,mt,attrconf[_id]
2473
if mt == 'id':
2474
# print ' ',
2475
row += sep+self._clean_csv(attrconf.get_linktab().format_ids([attrconf[_id]]), sep)
2476
else:
2477
row += sep+self._clean_csv('%s' % (attrconf.format_value(_id, show_unit=False)), sep)
2478
2479
# make sure there is no CR in the row!!
2480
# print row
2481
fd.write(row+'\n')
2482
2483
2484
class BaseObjman:
2485
"""
2486
Object management base methods to be inherited by all object managers.
2487
"""
2488
2489
def __init__(self, ident, is_plugin=False, **kwargs):
2490
# print 'BaseObjman.__init__',ident#,kwargs
2491
self._init_objman(ident, **kwargs)
2492
self.set_attrsman(Attrsman(self, is_plugin=is_plugin))
2493
# print 'BaseObjman.__init__',self.format_ident(),'parent=',self.parent
2494
self._init_attributes()
2495
self._init_constants()
2496
2497
def set_attrsman(self, attrsman):
2498
self._attrsman = attrsman
2499
return attrsman
2500
2501
def _init_objman(self, ident='no_ident', parent=None, name=None,
2502
managertype='basic', info=None, logger=None,
2503
xmltag=None, version=0.0):
2504
# print 'BaseObjman._init_objman',ident,logger,parent
2505
self.managertype = managertype
2506
self.ident = ident
2507
self.set_version(version)
2508
self.set_logger(logger)
2509
2510
#self._is_root = False
2511
self.parent = parent
2512
self.childs = {} # dict with attrname as key and child instance as value
2513
2514
self._info = info
2515
2516
self._is_saved = False
2517
2518
if name is None:
2519
self._name = self.format_ident()
2520
else:
2521
self._name = name
2522
2523
self.set_xmltag(xmltag)
2524
2525
# print ' self.parent',self.parent
2526
# must be called explicitely during __init__
2527
# self._init_attributes()
2528
# self._init_constants()
2529
2530
def _init_attributes(self):
2531
"""
2532
This is the place to add all attributes.
2533
This method will be called to initialize
2534
and after loading a saved object.
2535
Use this method also to update a version.
2536
"""
2537
pass
2538
2539
def _init_constants(self):
2540
"""
2541
This is the place to init any costants that are outside the management.
2542
Constants are not saved.
2543
This method will be called to initialize and after loading a saved object.
2544
"""
2545
pass
2546
2547
def set_version(self, version):
2548
2549
self._version = version
2550
2551
def get_version(self):
2552
if hasattr(self, '_version'):
2553
return self._version
2554
else:
2555
# for compatibility
2556
return 0.0
2557
2558
# def _upgrade_version(self):
2559
# pass
2560
2561
# def _init_xml(self,xmltag=None):
2562
# if xmltag is not None:
2563
# self.xmltag = xmltag
2564
# else:
2565
# self.xmltag = self.get_ident()
2566
2567
def reset(self):
2568
"""
2569
Resets all attributes to default values
2570
"""
2571
# print 'reset'
2572
for attrconfig in self.get_attrsman().get_configs(is_all=True):
2573
# print ' reset',attrconfig.attrname
2574
attrconfig.reset()
2575
2576
def clear(self):
2577
"""
2578
Clear tables and reset scalars.
2579
"""
2580
for attrconfig in self.get_attrsman().get_configs(is_all=True):
2581
attrconfig.clear()
2582
2583
self._init_constants()
2584
2585
def unplug(self):
2586
if self.plugin:
2587
self.plugin.unplug()
2588
2589
def set_xmltag(self, xmltag, xmlsep=' '):
2590
self.xmltag = xmltag
2591
self.xmlsep = xmlsep
2592
2593
def write_xml(self, fd, ident):
2594
if self.xmltag is not None:
2595
# figure out scalar attributes and child objects
2596
attrconfigs = []
2597
objconfigs = []
2598
for attrconfig in self.get_attrsman().get_configs(structs=STRUCTS_SCALAR):
2599
if (attrconfig.metatype == 'obj'): # better use self.childs
2600
if (attrconfig.get_value().xmltag is not None) & attrconfig.is_child():
2601
objconfigs.append(attrconfig)
2602
elif attrconfig.xmltag is not None:
2603
attrconfigs.append(attrconfig)
2604
2605
# start writing
2606
if len(attrconfigs) > 0:
2607
# there are scalar attributes
2608
fd.write(xm.start(self.xmltag, ident))
2609
for attrconfig in attrconfigs:
2610
attrconfig.write_xml(fd)
2611
2612
# are there child objects to write
2613
if len(objconfigs) > 0:
2614
fd.write(xm.stop())
2615
for attrconfig in objconfigs:
2616
attrconfig.get_value().write_xml(fd, ident+2)
2617
fd.write(xm.end(self.xmltag, ident))
2618
else:
2619
fd.write(xm.stopit())
2620
else:
2621
# no scalars
2622
fd.write(xm.begin(self.xmltag, ident))
2623
if len(objconfigs) > 0:
2624
for attrconfig in objconfigs:
2625
attrconfig.get_value().write_xml(fd, ident+2)
2626
fd.write(xm.end(self.xmltag, ident))
2627
2628
def get_logger(self):
2629
# print 'get_logger',self.ident,self._logger,self.parent
2630
if self._logger is not None:
2631
return self._logger
2632
else:
2633
return self.parent.get_logger()
2634
2635
def set_logger(self, logger):
2636
# print 'set_logger',self.ident,logger
2637
self._logger = logger
2638
2639
def __repr__(self):
2640
# return '|'+self._name+'|'
2641
return self.format_ident()
2642
2643
def is_modified(self):
2644
return self._attrsman.is_modified()
2645
2646
def set_modified(self, is_modified=True):
2647
self._attrsman.set_modified(is_modified)
2648
2649
def get_name(self):
2650
return self._name
2651
2652
def get_info(self):
2653
if self._info is None:
2654
return self.__doc__
2655
else:
2656
return self._info
2657
2658
def get_ident(self):
2659
return self.ident
2660
2661
def _format_ident(self, ident):
2662
if hasattr(ident, '__iter__'):
2663
return str(ident[0])+'#'+str(ident[1])
2664
else:
2665
return str(ident)
2666
2667
def format_ident(self):
2668
return self._format_ident(self.ident)
2669
2670
def format_ident_abs(self):
2671
s = ''
2672
# print 'format_ident_abs',self.get_ident_abs()
2673
for ident in self.get_ident_abs():
2674
s += self._format_ident(ident)+'.'
2675
return s[:-1]
2676
2677
def export_csv(self, filepath, sep=',',
2678
attrconfigs=None, groupnames=None,
2679
is_header=True, is_ident=False, is_timestamp=True,
2680
show_parentesis=True):
2681
"""
2682
Export scalars to file feed in csv format.
2683
"""
2684
print 'BaseObjman.export_csv', filepath, "*"+sep+"*", 'attrconfigs', attrconfigs, self.get_attrsman()
2685
fd = open(filepath, 'w')
2686
2687
# header
2688
if is_header:
2689
2690
row = self._clean_csv(self.get_name(), sep)
2691
if is_ident:
2692
row += sep+'(ident=%s)' % self.format_ident_abs()
2693
fd.write(row+'\n')
2694
if is_timestamp:
2695
now = datetime.now()
2696
fd.write(self._clean_csv(now.isoformat(), sep)+'\n')
2697
fd.write('\n\n')
2698
2699
self.get_attrsman().write_csv(fd, sep=sep,
2700
show_parentesis=show_parentesis, groupnames=groupnames,
2701
attrconfigs=attrconfigs)
2702
2703
fd.close()
2704
2705
def _clean_csv(self, row, sep):
2706
row = row.replace('\n', ' ')
2707
#row=row.replace('\b',' ')
2708
row = row.replace('\r', ' ')
2709
#row=row.replace('\f',' ')
2710
#row=row.replace('\newline',' ')
2711
row = row.replace(sep, ' ')
2712
return row
2713
2714
def get_root(self):
2715
# if hasattr(self,'_is_root'):
2716
# print 'get_root',self.ident,'is_root',self._is_root
2717
# if self._is_root:
2718
# return self
2719
2720
if self.parent is not None:
2721
return self.parent.get_root()
2722
else:
2723
return self
2724
2725
def get_ident_abs(self):
2726
"""
2727
Returns absolute identity.
2728
This is the ident of this object in the global tree of objects.
2729
If there is a parent objecty it must also be managed by the
2730
object manager.
2731
"""
2732
# print 'obj.get_ident_abs',self.ident,self.parent, type(self.parent)
2733
# if hasattr(self,'_is_root'):
2734
# print 'get_ident_abs',self.ident,'is_root',self._is_root
2735
# if self._is_root:
2736
# return (self.get_ident(),)# always return tuple
2737
2738
if self.parent is not None:
2739
return self.parent.get_ident_abs()+(self.ident,)
2740
else:
2741
return (self.get_ident(),) # always return tuple
2742
2743
def get_obj_from_ident(self, ident_abs):
2744
# print 'get_obj_from_ident',self.ident,ident_abs
2745
if len(ident_abs) == 1:
2746
# arrived at the last element
2747
# check if it corresponds to the present object
2748
if ident_abs[0] == self.ident:
2749
return self
2750
else:
2751
return None # could throw an error
2752
else:
2753
return self.get_childobj(ident_abs[1]).get_obj_from_ident(ident_abs[1:])
2754
2755
# this is an attemt to restore objects from
2756
# root objects without childs
2757
# def search_ident_abs(self, childobj):
2758
# """
2759
# Returns root and absolute ident for the found root.
2760
# """
2761
# #if hasattr(self,'_is_root'):
2762
# # print 'get_root',self.ident,'is_root',self._is_root
2763
# # if self._is_root:
2764
# # return self
2765
#
2766
# if self.parent is not None:
2767
# if self.parent.childs.has_key(childobj.ident)
2768
# return self.parent.get_root()
2769
# else:
2770
# return self
2771
2772
# def search_obj_from_ident(self, ident_abs, obj_init):
2773
#
2774
# #print 'get_obj_from_ident',self.ident,ident_abs
2775
# if len(ident_abs)==1:
2776
# # arrived at the last element
2777
# # check if it corresponds to the present object
2778
# if ident_abs[0] == self.ident:
2779
# return self
2780
# else:
2781
# return None # could throw an error
2782
# else:
2783
# return self.get_childobj(ident_abs[1]).get_obj_from_ident(ident_abs[1:])
2784
2785
def get_childobj(self, attrname):
2786
"""
2787
Return child instance
2788
"""
2789
if self.childs.has_key(attrname):
2790
config = self.childs[attrname]
2791
return config.get_value()
2792
else:
2793
return BaseObjman(self)
2794
2795
def set_child(self, childconfig):
2796
"""
2797
Set child childconfig
2798
"""
2799
self.childs[childconfig.attrname] = childconfig
2800
2801
def del_child(self, attrname):
2802
"""
2803
Return child instance
2804
"""
2805
del self.childs[attrname]
2806
2807
def get_parent(self):
2808
return self.parent
2809
2810
# def reset_parent(self, parent):
2811
# self.parent=parent
2812
2813
# def set_attrsman(self, attrsman):
2814
# # for quicker acces and because it is only on
2815
# # the attribute management is public and also directly accessible
2816
# #setattr(self, attrname,Attrsman(self))# attribute management
2817
# self._attrsman = attrsman
2818
# #return attrsman
2819
2820
def get_attrsman(self):
2821
return self._attrsman
2822
2823
def _getstate_specific(self, state):
2824
"""
2825
Called by __getstate__ to add/change specific states,
2826
before returning states.
2827
To be overridden.
2828
"""
2829
pass
2830
2831
def __getstate__(self):
2832
# print 'BaseObjman.__getstate__',self.ident,self._is_saved
2833
# print ' self.__dict__=\n',self.__dict__.keys()
2834
state = {}
2835
# if not self._is_saved:
2836
2837
# if self._is_saved:
2838
# # this message indicates a loop!!
2839
# print 'WARNING in __getstate__: object already saved',self.format_ident_abs()
2840
2841
# print ' save standart values'
2842
for attr in ATTRS_SAVE:
2843
if hasattr(self, attr):
2844
state[attr] = getattr(self, attr)
2845
2846
# print ' save all scalar stuctured attributes'
2847
# attrsman knows which and how
2848
# self._attrsman.save_values(state)
2849
#
2850
# values of configured attributes are not saved here
2851
# values are now ALWAYS stored in the value attribute of the
2852
# attrconfig and reset in main obj
2853
2854
# print ' save also attrsman'
2855
state['_attrsman'] = self._attrsman
2856
self._getstate_specific(state)
2857
2858
self._is_saved = True
2859
2860
# else:
2861
# print 'WARNING in __getstate__: object %s already saved'%self.ident
2862
return state
2863
2864
def __setstate__(self, state):
2865
# print '__setstate__',self
2866
2867
# this is always required, but will not be saved
2868
# self.plugins={}
2869
2870
for key in state.keys():
2871
# print ' set state',key
2872
self.__dict__[key] = state[key]
2873
2874
self._is_saved = False
2875
# done in init2_config...
2876
# set default values for all states tha have not been saved
2877
# for attr in self._config.keys():
2878
# if (not self._config[attr]['save']) & (not hasattr(self,attr)):
2879
# print ' config attr',attr
2880
# self.config(attr,**self._config[attr])
2881
2882
# set other states
2883
# self._setstate(state)
2884
2885
def init_postload_internal(self, parent):
2886
"""
2887
Called after set state.
2888
Link internal states and call constant settings.
2889
"""
2890
print 'BaseObjman.init_postload_internal', self.ident, 'parent:'
2891
# if parent is not None:
2892
# print parent.ident
2893
# else:
2894
# print 'ROOT'
2895
self.parent = parent
2896
self.childs = {}
2897
self._attrsman.init_postload_internal(self)
2898
2899
def init_postload_external(self):
2900
"""
2901
Called after set state.
2902
Link internal states.
2903
"""
2904
2905
#self._is_root = is_root
2906
# print 'init_postload_external',self.ident#,self._is_root
2907
# set default logger
2908
self.set_logger(Logger(self))
2909
# for child in self.childs.values():
2910
# child.reset_parent(self)
2911
self._attrsman.init_postload_external()
2912
self._init_attributes()
2913
self._init_constants()
2914
2915
2916
class TableMixin(BaseObjman):
2917
2918
def format_ident_row(self, _id):
2919
# print 'format_ident_row',_id
2920
return self.format_ident()+'['+str(_id)+']'
2921
2922
def format_ident_row_abs(self, _id):
2923
return self.format_ident_abs()+'['+str(_id)+']'
2924
2925
def get_obj_from_ident(self, ident_abs):
2926
# print 'get_obj_from_ident',self.ident,ident_abs,type(ident_abs)
2927
if len(ident_abs) == 1:
2928
# arrived at the last element
2929
# check if it corresponds to the present object
2930
ident_check = ident_abs[0]
2931
2932
# now 2 things can happen:
2933
# 1.) the ident is a simple string identical to ident of the object
2934
# in this case, return the whole object
2935
# 2.) ident is a tuple with string and id
2936
# in this case return object and ID
2937
# if hasattr(ident_check, '__iter__'):
2938
# #if (ident_check[0] == self.ident)&(ident_check[1] in self._ids):
2939
# if ident_check[1] in self._ids:
2940
# return (self, ident_check[1])
2941
# else:
2942
# return None # could throw an error
2943
# else:
2944
if ident_check == self.ident:
2945
return self
2946
else:
2947
childobj = self.get_childobj(ident_abs[1])
2948
return childobj.get_obj_from_ident(ident_abs[1:])
2949
2950
def get_childobj(self, ident):
2951
"""
2952
Return child instance.
2953
This is any object with ident
2954
"""
2955
if hasattr(ident, '__iter__'):
2956
# access of ObjsConf configured child
2957
# get object from column attrname
2958
attrname, _id = ident
2959
config = self.childs[attrname]
2960
return config[_id] # config.get_valueobj(_id)
2961
else:
2962
# access of ObjConf configured child
2963
# get object from attrname
2964
config = self.childs[ident]
2965
return config.get_value()
2966
2967
def __getstate__(self):
2968
# print '__getstate__',self.ident,self._is_saved
2969
# print ' self.__dict__=\n',self.__dict__.keys()
2970
state = {}
2971
if 1: # not self._is_saved:
2972
2973
# print ' save standart values'
2974
for attr in ATTRS_SAVE+ATTRS_SAVE_TABLE:
2975
if attr == 'plugin':
2976
plugin = self.__dict__[attr]
2977
if plugin is not None:
2978
state[attr] = True
2979
else:
2980
state[attr] = False
2981
2982
elif hasattr(self, attr):
2983
state[attr] = getattr(self, attr)
2984
2985
# save managed attributes !!!
2986
for attrconfig in self.get_configs(is_all=True):
2987
state[attrconfig.attrname] = attrconfig
2988
2989
# print ' save all scalar stuctured attributes'
2990
# attrsman knows which and how
2991
# self.save_values(state)
2992
2993
# print ' save also attrsman'
2994
#state['attrsman'] = self._attrsman
2995
self._is_saved = True
2996
2997
else:
2998
print 'WARNING in __getstate__: object %s already saved' % self.ident
2999
return state
3000
3001
def __setstate__(self, state):
3002
# print '__setstate__',self.ident
3003
3004
# this is always required, but will not be saved
3005
self.plugins = {}
3006
3007
for attr in state.keys():
3008
# print ' set state',key
3009
if attr == 'plugin':
3010
if state[attr] == True:
3011
self.__dict__[attr] = Plugin(self)
3012
else:
3013
self.__dict__[attr] = None
3014
else:
3015
self.__dict__[attr] = state[attr]
3016
3017
self._is_saved = False
3018
# done in init2_config...
3019
# set default values for all states tha have not been saved
3020
# for attr in self._config.keys():
3021
# if (not self._config[attr]['save']) & (not hasattr(self,attr)):
3022
# print ' config attr',attr
3023
# self.config(attr,**self._config[attr])
3024
3025
# set other states
3026
# self._setstate(state)
3027
3028
def init_postload_internal(self, parent):
3029
"""
3030
Called after set state.
3031
Link internal states.
3032
"""
3033
# print 'TableObjman.init_postload_internal',self.ident,'parent:',
3034
# if parent is not None:
3035
# print parent.ident
3036
# else:
3037
# print 'ROOT'
3038
3039
if not hasattr(self, '_attrs_nosave'):
3040
self._attrs_nosave = set(ATTRS_NOSAVE)
3041
3042
self.parent = parent
3043
self.childs = {}
3044
self.set_attrsman(self)
3045
Attrsman.init_postload_internal(self, self)
3046
3047
self._is_saved = False
3048
3049
def init_postload_external(self):
3050
"""
3051
Called after set state.
3052
Link internal states.
3053
"""
3054
Attrsman.init_postload_external(self)
3055
# no: BaseObjman.init_postload_external(self)
3056
self._init_attributes()
3057
self._init_constants()
3058
3059
def export_csv(self, filepath, sep=',',
3060
ids=None, attrconfigs=None, groupnames=None,
3061
is_header=True, is_ident=False, is_timestamp=True,
3062
show_parentesis=True, name_id='ID'):
3063
"""
3064
Export scalars to file feed in csv format.
3065
"""
3066
print 'TableMixin.export_csv', filepath, "*"+sep+"*" # ,'attrconfigs',attrconfigs,self.get_attrsman()
3067
fd = open(filepath, 'w')
3068
3069
# header
3070
if is_header:
3071
3072
row = self._clean_csv(self.get_name(), sep)
3073
if is_ident:
3074
row += sep+'(ident=%s)' % self.format_ident_abs()
3075
fd.write(row+'\n')
3076
if is_timestamp:
3077
now = datetime.now()
3078
fd.write(self._clean_csv(now.isoformat(), sep)+'\n')
3079
fd.write('\n\n')
3080
3081
self.get_attrsman().write_csv(fd, sep=sep, ids=ids,
3082
show_parentesis=show_parentesis, groupnames=groupnames,
3083
attrconfigs=attrconfigs, name_id='ID')
3084
3085
fd.close()
3086
3087
def clear_rows(self):
3088
if self.plugin:
3089
self.plugin.exec_events_ids(EVTDELITEM, self.get_ids())
3090
self._ids = []
3091
for colconfig in self.get_attrsman()._colconfigs:
3092
# print 'ArrayObjman.clear_rows',colconfig.attrname,len(colconfig.get_value())
3093
colconfig.clear()
3094
# print ' done',len(colconfig.get_value())
3095
3096
def clear(self):
3097
# print 'ArrayObjman.clear',self.ident
3098
# clear/reset scalars
3099
for attrconfig in self.get_attrsman().get_configs(structs=STRUCTS_SCALAR):
3100
attrconfig.clear()
3101
self.clear_rows()
3102
self.set_modified()
3103
3104
def _write_xml_body(self, fd, indent, objconfigs, idcolconfig_include_tab, colconfigs,
3105
objcolconfigs, xmltag_item, attrconfig_id, xmltag_id, ids, ids_xml):
3106
3107
# print '_write_xml_body ident,ids',self.ident,ids
3108
if ids is None:
3109
ids = self.get_ids()
3110
3111
if ids_xml is None:
3112
ids_xml = ids
3113
3114
for attrconfig in objconfigs:
3115
attrconfig.get_value().write_xml(fd, indent+2)
3116
3117
# check if columns contain objects
3118
#objcolconfigs = []
3119
scalarcolconfigs = colconfigs
3120
# for attrconfig in colconfigs:
3121
# if attrconfig.metatype == 'obj':
3122
# objcolconfigs.append(attrconfig)
3123
# else:
3124
# scalarcolconfigs.append(attrconfig)
3125
3126
for _id, id_xml in zip(ids, ids_xml):
3127
fd.write(xm.start(xmltag_item, indent+2))
3128
3129
# print ' make tag and id',_id
3130
if xmltag_id == '':
3131
# no id tag will be written
3132
pass
3133
elif (attrconfig_id is None) & (xmltag_id is not None):
3134
# use specified id tag and and specified id values
3135
fd.write(xm.num(xmltag_id, id_xml))
3136
3137
elif (attrconfig_id is not None):
3138
# use id tag and values of attrconfig_id
3139
attrconfig_id.write_xml(fd, _id)
3140
3141
# print ' write columns',len(scalarcolconfigs)>0,len(idcolconfig_include_tab)>0,len(objcolconfigs)>0
3142
for attrconfig in scalarcolconfigs:
3143
# print ' scalarcolconfig',attrconfig.attrname
3144
attrconfig.write_xml(fd, _id)
3145
3146
if (len(idcolconfig_include_tab) > 0) | (len(objcolconfigs) > 0):
3147
fd.write(xm.stop())
3148
3149
for attrconfig in idcolconfig_include_tab:
3150
# print ' include_tab',attrconfig.attrname
3151
attrconfig.write_xml(fd, _id, indent+4)
3152
3153
for attrconfig in objcolconfigs:
3154
# print ' objcolconfig',attrconfig.attrname
3155
attrconfig[_id].write_xml(fd, indent+4)
3156
fd.write(xm.end(xmltag_item, indent+2))
3157
else:
3158
fd.write(xm.stopit())
3159
3160
# print ' _write_xml_body: done'
3161
3162
def write_xml(self, fd, indent, xmltag_id='id', ids=None, ids_xml=None,
3163
is_print_begin_end=True, attrconfigs_excluded=[]):
3164
# print 'write_xml',self.ident#,ids
3165
if self.xmltag is not None:
3166
xmltag, xmltag_item, attrname_id = self.xmltag
3167
3168
if xmltag == '': # no begin end statements
3169
is_print_begin_end = False
3170
3171
if ids is not None:
3172
if not hasattr(ids, '__iter__'):
3173
ids = [ids]
3174
3175
if attrname_id == '': # no id info will be written
3176
attrconfig_id = None
3177
xmltag_id = ''
3178
3179
elif attrname_id is not None: # an attrconf for id has been defined
3180
attrconfig_id = getattr(self.get_attrsman(), attrname_id)
3181
xmltag_id = None # this will define the id tag
3182
else:
3183
attrconfig_id = None # native id will be written using xmltag_id from args
3184
3185
# print ' attrname_id,attrconfig_id',attrname_id,attrconfig_id
3186
# if attrconfig_id is not None:
3187
# print ' attrconfig_id',attrconfig_id.attrname
3188
3189
# figure out scalar attributes and child objects
3190
attrconfigs = []
3191
objconfigs = []
3192
colconfigs = []
3193
objcolconfigs = []
3194
idcolconfig_include_tab = []
3195
for attrconfig in self.get_attrsman().get_configs(is_all=True):
3196
# print ' check',attrconfig.attrname,attrconfig.xmltagis not None,attrconfig.is_colattr(),attrconfig.metatype
3197
if attrconfig == attrconfig_id:
3198
pass
3199
elif attrconfig in attrconfigs_excluded:
3200
pass
3201
elif attrconfig.is_colattr() & (attrconfig.metatype == 'obj'):
3202
objcolconfigs.append(attrconfig)
3203
elif (attrconfig.is_colattr()) & (attrconfig.metatype in ('ids', 'id')) & (attrconfig.xmltag is not None):
3204
if hasattr(attrconfig, "is_xml_include_tab"):
3205
if attrconfig.is_xml_include_tab:
3206
idcolconfig_include_tab.append(attrconfig)
3207
else:
3208
colconfigs.append(attrconfig)
3209
else:
3210
colconfigs.append(attrconfig)
3211
elif attrconfig.is_colattr() & (attrconfig.xmltag is not None):
3212
colconfigs.append(attrconfig)
3213
elif (attrconfig.metatype == 'obj'): # better use self.childs
3214
if (attrconfig.get_value().xmltag is not None) & attrconfig.is_child():
3215
objconfigs.append(attrconfig)
3216
elif attrconfig.xmltag is not None:
3217
attrconfigs.append(attrconfig)
3218
3219
# print ' attrconfigs',attrconfigs
3220
# print ' objconfigs',objconfigs
3221
# print ' idcolconfig_include_tab',idcolconfig_include_tab
3222
# print ' colconfigs',colconfigs
3223
# start writing
3224
if len(attrconfigs) > 0:
3225
# print ' there are scalar attributes'
3226
if is_print_begin_end:
3227
fd.write(xm.start(xmltag, indent))
3228
for attrconfig in attrconfigs:
3229
attrconfig.write_xml(fd)
3230
3231
# are there child objects to write
3232
if (len(objconfigs) > 0) | (len(colconfigs) > 0) | (len(idcolconfig_include_tab) > 0):
3233
fd.write(xm.stop())
3234
self._write_xml_body(fd, indent, objconfigs, idcolconfig_include_tab,
3235
colconfigs,
3236
objcolconfigs,
3237
xmltag_item, attrconfig_id,
3238
xmltag_id, ids, ids_xml)
3239
fd.write(xm.end(xmltag, indent))
3240
3241
else:
3242
fd.write(xm.stopit())
3243
else:
3244
# print ' no scalars'
3245
if is_print_begin_end:
3246
fd.write(xm.begin(xmltag, indent))
3247
self._write_xml_body(fd, indent, objconfigs, idcolconfig_include_tab,
3248
colconfigs,
3249
objcolconfigs,
3250
xmltag_item, attrconfig_id,
3251
xmltag_id, ids, ids_xml)
3252
3253
if is_print_begin_end:
3254
fd.write(xm.end(xmltag, indent))
3255
3256
3257
class TableObjman(Tabman, TableMixin):
3258
"""
3259
Table Object management manages objects with list and dict based columns.
3260
For faster operation use ArrayObjman in arrayman package, which requires numpy.
3261
"""
3262
3263
def __init__(self, ident, **kwargs):
3264
self._init_objman(ident, **kwargs)
3265
self._init_attributes()
3266
self._init_constants()
3267
3268
def _init_objman(self, ident, is_plugin=False, **kwargs):
3269
BaseObjman._init_objman(self, ident, managertype='table', **kwargs)
3270
Tabman.__init__(self, is_plugin=is_plugin)
3271
# self.set_attrsman(self)
3272
self.set_attrsman(self)
3273
3274
3275
###############################################################################
3276
if __name__ == '__main__':
3277
"""
3278
Test
3279
"""
3280
3281
pass
3282
3283