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