Path: blob/main/tools/contributed/sumopy/agilepy/lib_base/classman.py
169689 views
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo1# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.2# SUMOPy module3# Copyright (C) 2012-2021 University of Bologna - DICAM4# This program and the accompanying materials are made available under the5# terms of the Eclipse Public License 2.0 which is available at6# https://www.eclipse.org/legal/epl-2.0/7# This Source Code may also be made available under the following Secondary8# Licenses when the conditions for such availability set forth in the Eclipse9# Public License 2.0 are satisfied: GNU General Public License, version 210# or later which is available at11# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html12# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later1314# @file classman.py15# @author Joerg Schweizer16# @date 2012171819# python classman.py2021# TODO:22# - store old values in attrcons and recover with undo232425# To be or not to be. -- Shakespeare26# To do is to be. -- Nietzsche27# To be is to do. -- Sartre28# Do be do be do. -- Sinatra2930# save with is saved flag31# xml mixin32# different attrconfig classe (numbers, strings, lists, colors,...)333435import types36import os37import pickle38import sys39import string40import math41from collections import OrderedDict42from datetime import datetime43#import numpy as np44import xmlman as xm45from logger import Logger46from misc import get_inversemap4748##########495051# event triggers52# plugtype plugcode53EVTDEL = 0 # delete attribute54EVTSET = 1 # set attribute55EVTGET = 2 # get attribute56EVTADD = 3 # add/create attribute5758EVTDELITEM = 20 # delete attribute59EVTSETITEM = 21 # set attribute60EVTGETITEM = 22 # get attribute61EVTADDITEM = 23 # add/create attribute626364ATTRS_NOSAVE = ('value', 'plugin', '_obj', '_manager', 'get', 'set', 'add',65'del', 'delete', 'childs', 'parent', '_attrconfig_id_tab')66ATTRS_SAVE = ('ident', '_name', 'managertype', '_info', 'xmltag', '_attrs_nosave')67ATTRS_SAVE_TABLE = ('_is_localvalue', 'attrname', '_colconfigs', '_ids', '_inds', '_attrconfigs',68'_groups', 'plugin', '_is_indexing', '_index_to_id', '_id_to_index')6970STRUCTS_COL = ('odict', 'array')71STRUCTS_SCALAR = ('scalar', 'list', 'matrix', 'scalar.func')7273NUMERICTYPES = (types.BooleanType, types.FloatType, types.IntType, types.LongType, types.ComplexType)74STRINGTYPES = (types.StringType, types.UnicodeType)75NODATATYPES = (types.FunctionType, types.InstanceType, types.LambdaType)767778def save_obj(obj, filename, is_not_save_parent=False):79"""80Saves python object to a file with filename.81Filename may also include absolute or relative path.82If operation fails a False is returned and True otherwise.83"""84# print 'save_obj',is_not_save_parent,filename,obj.parent85try:86f = open(filename, 'wb')87except:88print 'WARNING in save: could not open', filename89return False9091if is_not_save_parent:92parent = obj.parent93obj.parent = None94# print ' before',is_not_save_parent,parent,obj.parent95pickle.dump(obj, f, protocol=2)96f.close()97# set all objects and attrubutes to unsaved again98# obj.set_unsaved()99# no, decided to eliminate _is_saved restriction100# print ' after',is_not_save_parent,parent,obj.parent101if is_not_save_parent:102obj.parent = parent103return True104105106def load_obj(filename, parent=None, is_throw_error=False):107"""108Reads python object from a file with filename and returns object.109Filename may also include absolute or relative path.110If operation fails a None object is returned.111"""112print 'load_obj', filename113114if is_throw_error:115f = open(filename, 'rb')116else:117try:118f = open(filename, 'rb')119except:120print 'WARNING in load_obj: could not open', filename121return None122123# try:124# print ' pickle.load...'125obj = pickle.load(f)126f.close()127128# init_postload_internal is to restore INTERNAL states from INTERNAL states129# print 'load_obj->init_postload_internal',obj.ident130obj.init_postload_internal(parent)131# print ' after init_postload_internal obj.parent',obj.parent132133# init_postload_external is to restore INTERNAL states from EXTERNAL states134# such as linking135#obj.init_postload_external(is_root = True)136obj.init_postload_external()137138# _init4_ is to do misc stuff when everything is set139# obj._init4_config()140141return obj142143# class ObjXmlMixin:144145146# class AttrXmlMixin:147148149class Plugin:150151def __init__(self, obj, is_enabled=True):152self._obj = obj # this can be either attrconf or main object153self._events = {}154self._has_events = False155self._is_enabled = is_enabled156157def get_obj(self):158return self._obj159160def unplug(self):161del self._events162self._events = {}163self._has_events = False164165def add_event(self, trigger, function):166"""167Standard plug types are automatically set but the system:168169"""170if not self._events.has_key(trigger):171self._events[trigger] = []172self._events[trigger].append(function)173self._has_events = True174175def del_event(self, trigger):176del self._events[trigger]177if len(self._events) == 0:178self._has_events = False179180def enable(self, is_enabled=True):181self._is_enabled = is_enabled182183def exec_events(self, trigger):184if self._has_events & self._is_enabled:185# print '**PuginMixin.exec_events',trigger,(EVTGETITEM,EVTGET)186# if trigger!=EVTGET:187# print ' call set_modified',self._obj188# self._obj.set_modified(True)189190for function in self._events.get(trigger, []):191function(self._obj)192193def exec_events_attr(self, trigger, attrconfig):194if self._has_events & self._is_enabled:195# print '**PuginMixin.exec_events',trigger,(EVTGETITEM,EVTGET)196# if trigger!=EVTGET:197# print ' call set_modified',self._obj198# self._obj.set_modified(True)199200for function in self._events.get(trigger, []):201function(self._obj, attrconfig)202203def exec_events_ids(self, trigger, ids):204"""205Executes all functions assigned for this trigger for multiple ids.206"""207if self._has_events & self._is_enabled:208# print '**ArrayConf._execute_events_keys',trigger,ids209# print ' _events',self._events210211for function in self._events.get(trigger, []):212function(self._obj, ids)213214215class AttrConf:216"""217Contains additional information on the object's attribute.218"""219220def __init__(self, attrname, default,221groupnames=[], perm='rw',222is_save=True,223# is_link = False, # define link class224is_copy=True,225name='', info='',226unit='',227xmltag=None,228xmlsep=' ',229xmlmap=None,230is_plugin=False,231struct='scalar',232metatype='',233is_returnval=True,234**attrs):235# if struct == 'None':236# if hasattr(default, '__iter__'):237# struct = 'scalar'238# else:239# struct = 'list'240241# these states will be saved and reloaded242self.attrname = attrname243self.groupnames = groupnames244self.metatype = metatype245self.struct = struct246247self._default = default248249self._is_save = is_save # will be set properly in set_manager250self._is_copy = is_copy251self._is_localvalue = True # value stored locally, set in set_manager252self._is_returnval = is_returnval253self._unit = unit254self._info = info255self._name = name256self._perm = perm257258# states below need to be resored after load259self._manager = None # set later by attrsman , necessary?260self._obj = None # parent object, set later by attrsman261262self._is_modified = False263self._is_saved = False264265self.init_plugin(is_plugin)266# self._init_xml(xmltag)267self.set_xmltag(xmltag, xmlsep, xmlmap)268269# set rest of attributes passed as keyword args270# no matter what they are used for271for attr, value in attrs.iteritems():272setattr(self, attr, value)273274def is_save(self):275return self._is_save276277def set_save(self, is_save):278if is_save:279self._manager.do_save_attr(self.attrname)280else:281self._manager.do_not_save_attr(self.attrname)282283def add_groupnames(self, groupnames):284self.groupnames = list(set(self.groupnames+groupnames))285self._manager.insert_groupnames(self)286287def del_groupname(self, groupname):288if groupname in self.groupnames:289self.groupnames.remove(groupname)290291# do this update in any case to be sure292# it disappears in the centralized database293self._manager.del_groupname(self)294295def has_group(self, groupname):296return groupname in self.groupnames297298def enable_plugin(self, is_enabled=True):299if self.plugin is not None:300self.plugin.enable(is_enabled)301302def get_metatype(self):303return self.metatype304305def init_plugin(self, is_plugin):306if is_plugin:307self.plugin = Plugin(self)308self.set = self.set_plugin309self.get = self.get_plugin310else:311self.plugin = None312313# def _init_xml(self,xmltag=None):314# if xmltag is not None:315# self.xmltag = xmltag316# else:317# self.xmltag = self.attrname318319def set_xmltag(self, xmltag, xmlsep=' ', xmlmap=None):320self.xmltag = xmltag321self.xmlsep = xmlsep322self.xmlmap = xmlmap323324def get_value_from_xmlattr(self, xmlattrs):325"""326Return a value of the correct data type327from the xml attribute object328329If this configuration is not found in xmlattrs330then None is returned.331"""332if (self.xmltag is not None):333if xmlattrs.has_key(self.xmltag):334return self.get_value_from_string(xmlattrs[self.xmltag])335else:336return None337338def get_value_from_string(self, s, sep=','):339"""340Returns the attribute value from a string in the correct type.341"""342343if self.metatype == 'color':344return xm.parse_color(s, sep)345346# TODO: allow arrays347# elif hasattr(val, '__iter__'):348# if len(val)>0:349# if hasattr(val[0], '__iter__'):350# # matrix351# fd.write(xm.mat(self.xmltag,val))352# else:353# # list354# fd.write(xm.arr(self.xmltag,val,self.xmlsep))355# else:356# # empty list357# #fd.write(xm.arr(self.xmltag,val))358# # don't even write empty lists359# pass360361elif self.xmlmap is not None:362imap = get_inversemap(self.xmlmap)363# print 'get_value_from_string',s,imap364if imap.has_key(s):365return imap[s]366else:367return self.get_numvalue_from_string(s)368369else:370return self.get_numvalue_from_string(s)371372def get_numvalue_from_string(self, s, valtype=None):373if valtype is None:374t = type(self._default)375else:376t = valtype377378if t in (types.UnicodeType, types.StringType):379return s380381elif t in (types.UnicodeType, types.StringType):382return s383384elif t in (types.LongType, types.IntType):385return int(s)386387elif t in (types.FloatType, types.ComplexType):388return float(s)389390elif t == types.BooleanType: # use default and hope it is no a numpy bool!!!391if s in ('1', 'True'):392return True393else:394return False395# 'MethodType', 'ModuleType', 'NoneType', 'NotImplementedType', 'ObjectType'396else:397return None # unsuccessful398399def write_xml(self, fd):400if self.xmltag is not None:401self._write_xml_value(self.get_value(), fd)402403def _write_xml_value(self, val, fd):404# print 'write_xml',self.xmltag,'is array',hasattr(val, '__iter__'),'xmlmap',self.xmlmap405if self.metatype == 'color':406fd.write(xm.color(self.xmltag, val))407408elif hasattr(val, '__iter__'):409if len(val) > 0:410if hasattr(val[0], '__iter__'):411# matrix412fd.write(xm.mat(self.xmltag, val))413else:414# list415fd.write(xm.arr(self.xmltag, val, self.xmlsep))416else:417# empty list418# fd.write(xm.arr(self.xmltag,val))419# don't even write empty lists420pass421422elif self.xmlmap is not None:423if self.xmlmap.has_key(val):424fd.write(xm.num(self.xmltag, self.xmlmap[val]))425else:426fd.write(xm.num(self.xmltag, val))427428elif hasattr(self, 'choices'):429if type(self.choices) == types.ListType:430fd.write(xm.num(self.xmltag, val))431else:432# print '_write_xml_value',self.attrname433# print ' val,self.choices.values()',val,self.choices.values()434i = self.choices.values().index(val)435fd.write(xm.num(self.xmltag, self.choices.keys()[i]))436437elif type(self._default) == types.BooleanType: # use default and hope it is no a numpy bool!!!438if val:439fd.write(xm.num(self.xmltag, 1))440else:441fd.write(xm.num(self.xmltag, 0))442443elif type(self._default) in (types.UnicodeType, types.StringType):444if len(val) > 0:445fd.write(xm.num(self.xmltag, val))446447else:448# scalar number or string449fd.write(xm.num(self.xmltag, val))450451def get_name(self):452return self._name453454def is_modified(self):455# print 'is_modified', self.attrname, self._is_modified456return self._is_modified457458def set_modified(self, is_modified):459self._is_modified = is_modified460461def set_manager(self, manager):462"""463Method to set manager to attribute configuration object.464This is either attribute manager or table manager.465Used by add method of AttrManager466"""467self._manager = manager468self._is_localvalue = manager.is_localvalue()469self.set_save(self._is_save)470471def get_manager(self):472"""473Method to get manager to attribute configuration object.474"""475return self._manager476477def set_obj(self, obj):478"""479Method to set instance of managed object.480Used by add method of AttrManager481"""482self._obj = obj483484def get_obj(self):485return self._obj486487def get(self):488# return attribute, overridden with indexing for array and dict struct489return self.get_value()490491def set(self, value):492# set attribute, overridden with indexing for array and dict struct493if value != self.get_value():494self.set_value(value)495self._is_modified = True496return value497498def get_plugin(self):499"""500Default get method with plugin for scalar attrs501"""502# return attribute, overridden with indexing for array and dict struct503self.plugin.exec_events(EVTGET)504505return self.get_value()506507def set_plugin(self, value):508"""509Default set method with plugin for scalar attrs510"""511# set attribute, overridden with indexing for array and dict struct512if value != self.get_value():513self.set_value(value)514self._is_modified = True515self.plugin.exec_events(EVTSET)516517return value518519def set_default(self, value):520self._default = value521522def get_default(self):523return self._default524525def get_init(self):526"""527Returns initialization of attribute.528Usually same as get_default for scalars.529Overridden by table configuration classes530"""531value = self.get_default()532# store locally if required533if self._is_localvalue:534self.value = value535return value536537def reset(self):538if self._is_localvalue:539self.value = self.get_default()540else:541setattr(self._obj, self.attrname, self.get_default())542543def clear(self):544self.reset()545546# def is_tableattr(self):547# return self.struct in ('dict','array','list')548549def set_perm(self, perm):550self._perm = perm551552def get_perm(self):553return self._perm554555def is_returnval(self):556if hasattr(self, '_is_returnval'): # for back compatibility557return self._is_returnval558else:559return True560561def is_readonly(self):562return 'w' not in self._perm563564def is_writable(self):565return 'w' in self._perm566567def is_editable(self):568"""Can attribute be edited """569return 'e' in self._perm570571def has_unit(self):572return self._unit != ''573574def has_info(self):575return self.get_info() is not None576577def is_colattr(self):578return hasattr(self, '__getitem__')579580def get_info(self):581if self._info is None:582return self.__doc__583else:584return self._info585586def format_unit(self, show_parentesis=False):587if self._unit in ('', None):588return ''589if show_parentesis:590return '[%s]' % self._unit591else:592return '%s' % self._unit593594def format_value(self, show_unit=False, show_parentesis=False):595if show_unit:596unit = ' '+self.format_unit(show_parentesis)597else:598unit = ''599# return repr(self.get_value())+unit600v = self.get_value()601# print 'format_value',self.attrname,v,type(v)602603if not hasattr(v, '__iter__'):604# print ' ',hasattr(self, 'digits_fraction'),(not math.isnan(v)),(not math.isinf(v))605if hasattr(self, 'digits_fraction'):606if (not math.isnan(v)) & (not math.isinf(v)):607printformat = "%."+str(self.digits_fraction)+"f"608return printformat % v+unit609else:610return str(v)+unit611else:612return str(v)+unit613else:614return str(v)+unit615616def format_symbol(self, show_parentesis=True):617if hasattr(self, 'symbol'):618symbol = self.symbol619else:620symbol = self._name621622return symbol+' '+self.format_unit(show_parentesis=show_parentesis)623624####625626def get_value(self):627# always return attribute, no indexing, no plugin628if self._is_localvalue:629return self.value630else:631return getattr(self._obj, self.attrname)632633def set_value(self, value):634# set entire attribute, no indexing, no plugin635# print 'AttrConf.set_value',self.attrname, self._is_localvalue, value, type(value)636if self._is_localvalue:637self.value = value638else:639return setattr(self._obj, self.attrname, value)640641def predelete(self):642"""643Cleanup operations before deleting644"""645if self._is_localvalue:646del self.value # delete value647else:648del self._obj.__dict__[self.attrname] # delete value649650# def init_presave_internal(self, man, obj):651# pass652# not a good idea to delete links, plugins here653654# def save_value(self, state):655# """656# Save attribute value of managed object to state dict.657#658# move this into __getstate__659#660# restore value in _obj during postllad_external661#662# make _getstate_ for speecific save663# """664# #print 'save_value',self.attrname,self._is_save, self._is_localvalue,665# #666# # Attention can be called fron __getstate__ of obj if _is_localvalue=False667# # or from __getstate__ of attribute config if _is_localvalue=True668669def _getstate_specific(self, state):670"""671Called by __getstate__ to add/change specific states,672before returning states.673To be overridden.674"""675pass676677def __getstate__(self):678# print 'AttrConf.__getstate__',self.get_obj().format_ident_abs(),self.attrname679# print ' self.__dict__=\n',self.__dict__.keys()680if self._is_saved:681# this message indicates a loop!!682print 'WARNING in __getstate__: Attribute already saved:', self.get_obj().format_ident_abs(), self.attrname683state = {}684for attr in self.__dict__.keys():685686if attr == 'plugin':687plugin = self.__dict__[attr]688if plugin is not None:689state[attr] = True690else:691state[attr] = False692693elif attr not in ATTRS_NOSAVE:694state[attr] = self.__dict__[attr]695696if self._is_save:697self._is_modified = False698state['value'] = self.get_value()699700self._getstate_specific(state)701# print ' state',state702return state703704def __setstate__(self, state):705# print '__setstate__',self706707# this is always required, but will not be saved708self.plugins = {}709710for attr in state.keys():711# print ' state key',attr, state[attr]712# done in init_postload_internal...713# if attr=='plugin':714# if state[attr]==True:715# self.__dict__[attr] = Plugin(self)716# else:717# self.__dict__[attr]= None718# else:719self.__dict__[attr] = state[attr]720721def init_postload_internal(self, man, obj):722# print 'AttrConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'obj:',obj.ident723724self.set_manager(man)725self.set_obj(obj)726self.init_plugin(self.plugin)727728# set initial values for unsafed attributes729if not self._is_save:730self.set_value(self.get_init())731else:732if self._is_localvalue:733# OK self.value already set in __setstate__734pass735else:736setattr(self._obj, self.attrname, self.value) # TODO: could be made nicer with method737del self.value # no longer needed738739# this attribute became compulsory740if not hasattr(self, 'xmlmap'):741self.xmlmap = None742743# print ' check',hasattr(self,'value')744# print ' value=',self.get_value()745self._is_saved = False746747def init_postload_external(self):748pass749750751class NumConf(AttrConf):752"""753Contains additional information on the object's attribute.754Here specific number related attributes are defined.755"""756757def __init__(self, attrname, default,758digits_integer=None, digits_fraction=None,759minval=None, maxval=None,760**kwargs):761self.min = minval762self.max = maxval763self.digits_integer = digits_integer764self.digits_fraction = digits_fraction765766AttrConf.__init__(self, attrname, default, metatype='number',767**kwargs768)769770771class ListConf(AttrConf):772"""773Specifies a list of objects.774Objects may be editable or selectable in the GUI775"""776777def __init__(self, attrname, default,778sep=',', valtype=None, is_fixedlength=False,779perm='rw', **kwargs):780#self._is_child = is_child781if valtype is None:782if len(default) > 0:783valtype = type(default[0])784else:785valtype = types.UnicodeType786787AttrConf.__init__(self, attrname, default,788struct='scalar',789metatype='list',790sep=sep,791valtype=valtype,792is_fixedlength=is_fixedlength,793perm=perm,794**kwargs795)796797def get_value_from_string(self, s, sep=None):798"""799Returns the attribute value from a string in the correct type.800"""801value = []802for val in s.split(self.sep):803value.append(self.get_numvalue_from_string(val, valtype=self.valtype))804805return value806807808class ObjConf(AttrConf):809"""810Contains additional information on the object's attribute.811Configures Pointer to another object .812This other object must have an ident.813it can be either a child (then it will be saved)814or a link (then only the id will saved)815If it is a child the is_child = True (default value)816"""817818def __init__(self, valueobj, is_child=True, **kwargs):819attrname = valueobj.get_ident()820self._is_child = is_child821AttrConf.__init__(self, attrname, valueobj,822struct='scalar',823metatype='obj',824perm='r',825**kwargs826)827828def set_obj(self, obj):829"""830Method to set instance of managed object.831Used by add method of AttrManager832"""833# print 'ObjConf.set_obj',self.attrname,obj.ident834AttrConf.set_obj(self, obj)835836if self._is_child:837# tricky: during first initialization838# child instance is stored in default839obj.set_child(self)840841def predelete(self):842AttrConf.predelete(self)843if self._is_child:844self.get_obj().del_child(self.attrname)845846def reset(self):847if self._is_child:848self.get_value().reset()849850def clear(self):851if self._is_child:852self.get_value().clear()853854def is_child(self):855return self._is_child856857def _getstate_specific(self, state):858"""859Called by __getstate__ to add/change specific states,860before returning states.861To be overridden.862"""863864# print 'ObjConf._getstate_specific',self.attrname,self._is_child,self._is_save865if self._is_save:866if self._is_child:867# OK self.value already set in868pass869else:870# print ' remove object reference from value and create ident'871state['value'] = None872if self.get_value() is not None:873# print ' found object',self.get_value().get_ident_abs()874state['_ident_value'] = self.get_value().get_ident_abs()875else:876print 'WARNING in ObjConf._getstate_specific', self.attrname, 'lost linked object'877state['_ident_value'] = []878# print ' ',879880def is_modified(self):881# if self._is_child882#is_modified = self.get_value().is_modified()883# print 'is_modified', self.attrname, is_modified884return self.get_value().is_modified()885886def set_modified(self, is_modified):887if self._is_child:888self.get_value().set_modified(is_modified)889890def write_xml(self, fd):891"""892Objects are not written here, but in write_xml of the parent obj.893"""894pass895896def init_postload_internal(self, man, obj):897# print 'ObjConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'parent obj:',obj.ident898899AttrConf.init_postload_internal(self, man, obj)900if self._is_child:901# print ' make sure children get initialized'902# self.get_value().init_postload_internal(obj)903# print ' call init_postload_internal of',self.get_value().ident,self.get_value(),self.get_value().__class__,self.get_value().init_postload_internal904self.get_value().init_postload_internal(obj)905906def init_postload_external(self):907# print 'ObjConf.init_postload_external',self.attrname,self._is_child908if self._is_child:909# restore normally910AttrConf.init_postload_external(self)911self.get_value().init_postload_external()912else:913# Substitute absolute ident with link object.914# Called from init_postload_external of attrsman during load_obj915#916ident_abs = self._ident_value917if len(ident_abs) > 0:918# print 'reset_linkobj',self.attrname,ident_abs919obj = self.get_obj()920rootobj = obj.get_root()921# print ' rootobj',rootobj.ident922linkobj = rootobj.get_obj_from_ident(ident_abs)923# print ' linkobj',linkobj.ident924self.set_value(linkobj)925else:926print 'WARNING in ObjConf._getstate_specific', self.attrname, 'lost linked object'927self.set_value(BaseObjman('lost_object'))928929# def get_valueobj(self):930# """931# This is called by get_childobj to retrive the child instance.932# """933# return self.get_value()934935def get_name(self):936return self.get_value().get_name()937938def get_info(self):939return self.get_value().__doc__940941def format_value(self, show_unit=False, show_parentesis=False):942return repr(self.get_value())943944945class FuncConf(AttrConf):946"""947Configures a function.948The function with name funcname must be a method of the object.949Default value is used to specify the type of output.950"""951952def __init__(self, attrname, funcname, exampleoutput, struct='scalar.func', perm='r', **kwargs):953self.funcname = funcname954955AttrConf.__init__(self, attrname, exampleoutput,956struct=struct,957perm=perm,958is_save=False,959**kwargs960)961962def set_obj(self, obj):963AttrConf.set_obj(self, obj)964if self._info == '':965self._info = getattr(self._obj, self.funcname).__doc__966967def get_value(self):968# print 'get_value',self.attrname969# always return attribute, no indexing, no plugin970return getattr(self._obj, self.funcname)()971# if self._is_localvalue:972# return self.value973# else:974# return getattr(self._obj, self.attrname)975976def get_function(self):977# print 'get_function',self.attrname978return getattr(self._obj, self.funcname)979980def set_value(self, value):981# set entire attribute, no indexing, no plugin982# print 'AttrConf.set_value',self.attrname, self._is_localvalue, value, type(value)983# this will run the function and return a value984return self.get_function()985986def is_modified(self):987return False988989def reset(self):990pass991992def clear(self):993pass994995996class Indexing:997"""998Mixing to allow any column attribute to be used as index.999"""10001001def _init_indexing(self):1002"""1003Init Indexing management attributes.1004"""10051006self._index_to_id = {} # OrderedDict()10071008# this updates index if values already exist1009if hasattr(self, 'value'):1010ids = self.get_obj().get_ids()1011self.add_indices(ids, self[ids])10121013def reset_index(self):1014self._init_indexing()10151016def get_indexmap(self):1017return self._index_to_id10181019def get_id_from_index(self, index):1020return self._index_to_id[index]10211022def has_indices(self, indices):1023ans = len(indices)*[False]1024for i in range(len(indices)):1025if self._index_to_id.has_key(indices[i]):1026ans[i] = True10271028return ans10291030def has_index(self, index):1031return self._index_to_id.has_key(index)10321033def get_ids_from_indices(self, indices):1034ids = len(indices)*[0]1035for i in range(len(indices)):1036# if not self._index_to_id.has_key(indices[i]):1037# print 'WARNING from get_ids_from_indices: no index',indices[i]1038# print self._index_to_id1039ids[i] = self._index_to_id[indices[i]]1040return ids10411042def get_ids_from_indices_save(self, indices):1043ids = len(indices)*[0]1044for i in range(len(indices)):1045if not self._index_to_id.has_key(indices[i]):1046ids[i] = -11047else:1048ids[i] = self._index_to_id[indices[i]]1049return ids10501051# use set instead of add10521053def add_indices(self, ids, indices):1054for _id, index in zip(ids, indices):1055self.add_index(_id, index)10561057def add_index(self, _id, index):1058self._index_to_id[index] = _id10591060def rebuild_indices(self):1061for idx in self._index_to_id.keys():1062del self._index_to_id[idx]1063ids = self.get_obj().get_ids()1064self.add_indices(ids, self[ids])10651066def del_indices(self, ids):10671068for _id in ids:1069self.del_index(_id)10701071def set_index(self, _id, index):1072# print 'set_index',self.attrname,_id, index1073# print ' B_index_to_id',self._index_to_id1074self.del_index(_id)1075self.add_index(_id, index)1076# print ' A_index_to_id',self._index_to_id10771078def set_indices(self, ids, indices):1079self.del_indices(ids)1080self.add_indices(ids, indices)10811082def del_index(self, _id):1083index = self[_id]1084# when index is added (with set) no previous index value exists1085if self._index_to_id.has_key(index):1086del self._index_to_id[index]10871088def get_ids_sorted(self):1089# print 'get_ids_sorted',self.value1090# print ' _index_to_id',self._index_to_id1091# print ' sorted',sorted(self._index_to_id.iteritems())1092return OrderedDict(sorted(self._index_to_id.iteritems())).values()10931094# def indexset(self, indices, values):1095# no! set made with respective attribute1096# print 'indexset',indices1097# print ' ids=',self.get_ids_from_indices(indices)1098# print ' values=',values1099# self[self.get_ids_from_indices(indices)] = values110011011102class ColConf(Indexing, AttrConf):1103"""1104Basic column configuration.1105Here an ordered dictionary is used to represent the data.1106#>>> from collections import OrderedDict1107#>>> spam = OrderedDict([('s',(1,2)),('p',(3,4)),('a',(5,6)),('m',(7,8))])1108>>> spam.values()11091110"""1111# def __init__(self, **attrs):1112# print 'ColConf',attrs11131114def __init__(self, attrname, default, is_index=False, **attrs):1115# print 'ColConf',attrs1116self._is_index = is_index1117AttrConf.__init__(self, attrname, default,1118struct='odict',1119**attrs)11201121if is_index:1122self._init_indexing()11231124def is_index(self):1125return self._is_index11261127def get_defaults(self, ids):1128# create a list, should work for all types and dimensions1129# default can be scalar or an array of any dimension1130# print '\n\nget_defaults',self.attrname,ids,self.get_default()1131values = []1132for _id in ids:1133values.append(self.get_default())1134# len(ids)*self.get_default() # makes links, not copies1135return values11361137def get_init(self):1138"""1139Returns initialization of attribute.1140Usually same as get_default for scalars.1141Overridden by table configuration classes1142"""1143ids = self._manager.get_ids()11441145# print '\n\nget_init',self.attrname,ids1146values = self.get_defaults(ids)1147i = 01148odict = OrderedDict()1149for _id in ids:1150odict[_id] = values[i]1151i += 11152# store locally if required1153if self._is_localvalue:1154self.value = odict1155# pass on to calling instance1156# in this cas the data is stored under self._obj1157return odict11581159def reset(self):1160# this reset works also for np arrays!1161odict = self.get_init()1162if not self._is_localvalue:1163setattr(self._obj, self.attrname, odict)1164if self._is_index:1165self.reset_index()11661167def init_plugin(self, is_plugin):1168if is_plugin:1169self.plugin = Plugin(self)1170self.set = self.set_plugin1171self.get = self.get_plugin1172self.add = self.add_plugin1173self.delete = self.delete_plugin1174else:1175self.plugin = None11761177def write_xml(self, fd, _id):1178if self.xmltag is not None:1179self._write_xml_value(self[_id], fd)11801181def __delitem__(self, ids):1182# print ' before=\n',self.__dict__[attr]1183#attr = self.attrconf.get_attr()1184if hasattr(ids, '__iter__'):1185if self._is_index:1186self.del_indices(ids)11871188array = self.get_value()1189for _id in ids:1190del array[_id]11911192else:1193if self._is_index:1194self.del_index(ids)11951196del self.get_value()[ids]11971198def delete_item(self, _id):1199# print ' before=\n',self.__dict__[attr]1200#attr = self.attrconf.get_attr()1201del self.get_value()[_id]12021203def __getitem__(self, ids):1204# print '__getitem__',key1205if hasattr(ids, '__iter__'):1206items = len(ids)*[None]1207i = 01208array = self.get_value()1209for _id in ids:1210items[i] = array[_id]1211i += 11212return items1213else:1214return self.get_value()[ids]12151216def __setitem__(self, ids, values):1217# print '__setitem__',ids,values,type(self.get_value())1218if hasattr(ids, '__iter__'):1219if self._is_index:1220self.set_indices(ids, values) # must be set before setting new value1221i = 01222array = self.get_value()1223for _id in ids:1224array[_id] = values[i]1225i += 11226# if self._is_index:1227# self.add_indices(ids, values)1228else:12291230if self._is_index:1231self.set_index(ids, values) # must be set before setting new value1232self.get_value()[ids] = values12331234# if self._is_index:1235# self.add_index(ids, values)12361237def add(self, ids, values=None):1238if not hasattr(ids, '__iter__'):1239_ids = [ids]1240if values is not None:1241_values = [values]1242else:1243_ids = ids1244_values = values12451246if values is None:1247_values = self.get_defaults(_ids)12481249# print 'add ids, _values',ids, _values1250# trick to prevent updating index before value is added1251if self._is_index:1252is_index_backup = True1253self._is_index = False1254else:1255is_index_backup = False12561257self[_ids] = _values12581259if is_index_backup:1260self._is_index = True1261self.add_indices(_ids, _values)12621263self._is_modified = True12641265def add_plugin(self, ids, values=None):1266if not hasattr(ids, '__iter__'):1267_ids = [ids]1268if values is not None:1269_values = [values]1270else:1271_ids = ids1272_values = values12731274# print 'add ids, _values',ids, _values1275if values is None:1276_values = self.get_defaults(_ids)1277# trick to prevent updating index before value is added1278if self._is_index:1279is_index_backup = True1280self._is_index = False1281else:1282is_index_backup = False12831284self[_ids] = _values12851286if is_index_backup:1287self._is_index = True1288self.add_indices(_ids, _values)12891290self._is_modified = True12911292if self.plugin:1293self.plugin.exec_events_ids(EVTADDITEM, _ids)12941295def get(self, ids):1296"""1297Central function to get the attribute value associated with ids.1298should be overridden by specific array configuration classes1299"""1300return self[ids]13011302def get_plugin(self, ids):1303"""1304Central function to get the attribute value associated with ids.1305should be overridden by specific array configuration classes1306"""1307if self._plugin:1308if not hasattr(ids, '__iter__'):1309self.plugin.exec_events_ids(EVTGETITEM, [ids])1310else:1311self.plugin.exec_events_ids(EVTGETITEM, ids)1312return self[ids]13131314def set(self, ids, values):1315"""1316Returns value of array element for all ids.1317"""13181319self[ids] = values1320self._is_modified = True1321# print 'set',self.attrname1322if self._is_index:1323self.set_indices(ids, values)13241325def set_plugin(self, ids, values):1326"""1327Returns value of array element for all ids.1328"""1329self[ids] = values1330self._is_modified = True1331# print 'set',self.attrname13321333if self.plugin:1334if not hasattr(ids, '__iter__'):1335self.plugin.exec_events_ids(EVTSETITEM, [ids])1336else:1337self.plugin.exec_events_ids(EVTSETITEM, ids)1338if self._is_index:1339self.set_indices(ids, values)13401341def delete(self, ids):1342"""1343removes key from array structure1344To be overridden1345"""1346del self[ids]1347self._is_modified = True13481349def delete_plugin(self, ids):1350"""1351removes key from array structure1352To be overridden1353"""1354if self.plugin:1355if not hasattr(ids, '__iter__'):1356self.plugin.exec_events_ids(EVTGETITEM, [ids])1357else:1358self.plugin.exec_events_ids(EVTGETITEM, ids)13591360del self[ids]1361self._is_modified = True13621363def format_value(self, _id, show_unit=False, show_parentesis=False):1364if show_unit:1365unit = ' '+self.format_unit(show_parentesis)1366else:1367unit = ''1368# return repr(self[_id])+unit13691370#self.min = minval1371#self.max = maxval1372#self.digits_integer = digits_integer1373#self.digits_fraction = digits_fraction1374val = self[_id]1375tt = type(val)13761377if tt in (types.LongType, types.IntType):1378return str(val)+unit13791380elif tt in (types.FloatType, types.ComplexType):1381if hasattr(attrconf, 'digits_fraction'):1382digits_fraction = self.digits_fraction1383else:1384digits_fraction = 31385return "%."+str(digits_fraction)+"f" % (val)+unit13861387else:1388return str(val)+unit13891390# return str(self[_id])+unit13911392def format(self, ids=None):1393# TODO: incredibly slow when calling format_value for each value1394text = ''13951396if ids is None:1397ids = self._manager.get_ids()1398if not hasattr(ids, '__iter__'):1399ids = [ids]14001401#unit = self.format_unit()1402attrname = self.attrname1403for id in ids:1404text += '%s[%d] = %s\n' % (attrname, id, self.format_value(id, show_unit=True))14051406return text[:-1] # remove last newline140714081409class NumcolConf(ColConf):1410def __init__(self, attrname, default,1411digits_integer=None, digits_fraction=None,1412minval=None, maxval=None,1413**attrs):1414self.min = minval1415self.max = maxval1416self.digits_integer = digits_integer1417self.digits_fraction = digits_fraction14181419ColConf.__init__(self, attrname, default, **attrs)142014211422class IdsConf(ColConf):1423"""1424Column, where each entry is the id of a single Table.1425"""14261427def __init__(self, attrname, tab, id_default=-1, is_index=False, perm='r', **kwargs):1428self._is_index = is_index1429self._tab = tab14301431AttrConf.__init__(self, attrname,1432id_default, # default id1433struct='odict',1434metatype='id',1435perm=perm,1436**kwargs1437)1438self.init_xml()1439# print 'IdsConf.__init__',attrname1440# print ' ',self._tab.xmltag,self._attrconfig_id_tab14411442def set_linktab(self, tab):1443self._tab = tab14441445def get_linktab(self):1446return self._tab14471448def init_xml(self):1449# print 'init_xml',self.attrname1450if self._tab.xmltag is not None:14511452# necessary?? see ObjMan.write_xml1453xmltag_tab, xmltag_item_tab, attrname_id_tab = self._tab.xmltag1454if (attrname_id_tab is None) | (attrname_id_tab is ''):1455self._attrconfig_id_tab = None1456else:1457self._attrconfig_id_tab = getattr(self._tab, attrname_id_tab) # tab = tabman !14581459if not hasattr(self, 'is_xml_include_tab'):1460# this means that entire table rows will be included1461self.is_xml_include_tab = False1462# print ' xmltag_tab, xmltag_item_tab, attrname_id_tab',xmltag_tab, xmltag_item_tab, attrname_id_tab,self.is_xml_include_tab14631464else:1465self._attrconfig_id_tab = None1466self.is_xml_include_tab = False14671468def write_xml(self, fd, _id, indent=0):1469if (self.xmltag is not None) & (self[_id] >= 0):1470if self._attrconfig_id_tab is None:1471self._write_xml_value(self[_id], fd)1472elif self.is_xml_include_tab:1473# this means that entire table rows will be included1474self._tab.write_xml(fd, indent, ids=self[_id], is_print_begin_end=False)1475else:1476self._write_xml_value(self._attrconfig_id_tab[self[_id]], fd)14771478def _write_xml_value(self, val, fd):1479# print 'write_xml',self.xmltag,hasattr(val, '__iter__')1480if hasattr(val, '__iter__'):1481if len(val) > 0:1482if hasattr(val[0], '__iter__'):1483# matrix1484fd.write(xm.mat(self.xmltag, val))1485else:1486# list1487fd.write(xm.arr(self.xmltag, val, self.xmlsep))1488else:1489# empty list1490# fd.write(xm.arr(self.xmltag,val))1491# don't even write empty lists1492pass14931494elif type(self._default) in (types.UnicodeType, types.StringType):1495if len(val) > 0:1496fd.write(xm.num(self.xmltag, val))14971498else:1499# scalar number or string1500fd.write(xm.num(self.xmltag, val))15011502def get_defaults(self, ids):1503# create a list, should work for all types and dimensions1504# default can be scalar or an array of any dimension1505# print '\n\nget_defaults',self.attrname,ids,self.get_default()1506return len(ids)*[self.get_default()]15071508def _getstate_specific(self, state):1509"""1510Called by __getstate__ to add/change specific states,1511before returning states.1512To be overridden.1513"""1514if self._is_save:1515# if self._is_child:1516# # OK self.value already set in1517# pass1518# else:1519# # remove table reference and create ident1520# print '_getstate_specific',self._tab.get_ident_abs()1521state['_tab'] = None1522state['_ident_tab'] = self._tab.get_ident_abs()15231524def init_postload_internal(self, man, obj):1525# print 'IdsConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'obj:',obj.ident15261527AttrConf.init_postload_internal(self, man, obj)1528# if self._is_child:1529# print ' make sure children get initialized'1530# print ' call init_postload_internal of',self._tab.ident1531# self._tab.init_postload_internal(obj)15321533def init_postload_external(self):1534# if self._is_child:1535# # restore normally1536# AttrConf.init_postload_external(self)1537# self._tab.init_postload_external()1538# else:15391540# Substitute absolute ident with link object.1541# Called from init_postload_external of attrsman during load_obj1542#1543ident_abs = self._ident_tab1544# print 'reset_linkobj',self.attrname,ident_abs1545obj = self.get_obj()1546rootobj = obj.get_root()1547# print ' rootobj',rootobj.ident1548linkobj = rootobj.get_obj_from_ident(ident_abs)1549# print ' linkobj',linkobj.ident1550self._tab = linkobj1551self.init_xml()15521553def is_modified(self):1554return False155515561557class TabIdsConf(ColConf):1558"""1559Column, where each entry contains a tuple with table object and id.1560"""15611562def __init__(self, attrname, is_index=False, **kwargs):1563self._is_index = is_index1564AttrConf.__init__(self, attrname,1565-1, # default id1566struct='odict',1567metatype='tabids',1568**kwargs1569)15701571def get_defaults(self, ids):1572# create a list, should work for all types and dimensions1573# default can be scalar or an array of any dimension1574# print '\n\nget_defaults',self.attrname,ids,self.get_default()1575return len(ids)*[(None, -1)]15761577def reset(self):1578# TODO: this will reset all the tables1579# instead should reset only the specified ids1580if self._is_child:1581for tab, ids in self.get_value():1582tab.reset()15831584def clear(self):1585self.reset()1586# necessary? because tbles have been cleared from manager1587# if self._is_child:1588# for tab, ids in self.get_value():1589# tab.clear()15901591def _getstate_specific(self, state):1592"""1593Called by __getstate__ to add/change specific states,1594before returning states.1595To be overridden.1596"""1597if self._is_save:1598n = len(state['value'])1599state['value'] = None1600_tabids_save = n*[None]1601i = 01602for tab, ids in self.get_value():1603_tabids_save[i] = [tab.get_ident_abs(), ids]1604i += 11605state['_tabids_save'] = _tabids_save16061607def init_postload_internal(self, man, obj):1608# print 'IdsConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'obj:',obj.ident16091610AttrConf.init_postload_internal(self, man, obj)1611# if self._is_child:1612# print ' make sure children get initialized'1613# print ' call init_postload_internal of',self._tab.ident1614# self._tab.init_postload_internal(obj)16151616def init_postload_external(self):1617# if self._is_child:1618# # restore normally1619# AttrConf.init_postload_external(self)1620# self._tab.init_postload_external()1621# else:16221623# Substitute absolute ident with link object.1624# Called from init_postload_external of attrsman during load_obj1625#1626#ident_abs = self._ident_tab1627# print 'reset_linkobj',self.attrname,ident_abs1628#obj = self.get_obj()1629#rootobj = obj.get_root()1630# print ' rootobj',rootobj.ident1631#linkobj = rootobj.get_obj_from_ident(ident_abs)1632# print ' linkobj',linkobj.ident1633#self._tab = linkobj16341635# Substitute absolute ident with link object.1636# Called from init_postload_external of attrsman during load_obj1637#1638_tabids_save = self._tabids_save1639#ident_abs = self._ident_value1640# print 'init_postload_external',self.attrname,_tabids_save1641obj = self.get_obj()1642rootobj = obj.get_root()1643# print ' rootobj',rootobj.ident1644tabids = len(self._tabids_save)*[None]1645i = 01646for tabident, ids in self._tabids_save:1647tab = rootobj.get_obj_from_ident(tabident)1648# print ' ',tab.get_ident_abs(), ids1649tabids[i] = [tab, ids]1650i += 116511652self.set_value(tabids)16531654def is_modified(self):1655return False165616571658class ObjsConf(ColConf):1659"""1660Column, where each entry is an object of class objclass with1661ident= (attrname, id).1662"""1663# TODO:1664# there is a problems with objects that are stored here1665# in particular if objects are Table. What is their correct ident1666# or absolute ident. Currently it is not correct.1667# This leads to incorrect referencing when linked from elsewhere1668# for example within TabIdListArrayConf1669# .get_ident_abs() needs to to be correct, such that1670# get_obj_from_ident can locate them1671# maybe it is not an issue of ObjsConf itself,1672# but the Objects stored must have a special getident method16731674def __init__(self, attrname, is_index=False, **kwargs):1675self._is_index = is_index1676self._is_child = True # at the moment no links possible1677AttrConf.__init__(self, attrname,1678None, # BaseObjman('empty'), # default id1679struct='odict',1680metatype='obj',1681perm='r',1682**kwargs1683)16841685def set_obj(self, obj):1686"""1687Method to set instance of managed object.1688Used by add method of AttrManager1689"""1690# print 'set_obj',self.attrname,obj.ident1691AttrConf.set_obj(self, obj)16921693# if self._is_child:1694obj.set_child(self)16951696# def get_valueobj(self, id = None):1697# """1698# This is called by get_childobj to retrive the child instance.1699# Here this is just the table.1700# """1701# return self._tab17021703def predelete(self):1704AttrConf.predelete(self)1705# if self._is_child:1706self.get_obj().del_child(self.attrname)17071708# def _getstate_specific(self, state):1709# """1710# Called by __getstate__ to add/change specific states,1711# before returning states.1712# To be overridden.1713# """1714# if self._is_save:1715# if self._is_child:1716# # OK self.value already set in1717# pass1718# else:1719# # remove column reference and create column with idents1720# state['value']= None1721# idents_obj = OrderedDict()1722# linkobjs = self.get_value()1723# for _id in self.get_ids():1724# idents_obj[_id] = linkobjs[_id].get_ident_abs()1725# state['_idents_obj'] = idents_obj17261727def init_postload_internal(self, man, obj):1728# print 'ObjsConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'obj:',obj.ident17291730AttrConf.init_postload_internal(self, man, obj)1731# if self._is_child:17321733# make sure all children in column get initialized1734# print ' make sure childrenS get initialized'1735childobjs = self.get_value()17361737obj = self.get_obj()1738# print 'init_postload_internal',self.attrname,obj,obj.ident1739for _id in obj.get_ids():1740# print ' call init_postload_internal of',childobjs[_id].ident1741childobjs[_id].init_postload_internal(obj) # attention obj is the parent object!17421743def reset(self):1744# print 'ObjsConf.reset',self.get_value(),len(self.get_obj().get_ids())1745#obj = self.get_obj()1746# print 'init_postload_internal',self.attrname,obj,obj.ident1747childobjs = self.get_value()1748for _id in self.get_obj().get_ids():1749# print ' call reset of',childobjs[_id].ident,_id1750childobjs[_id].reset()17511752def clear(self):1753odict = self.get_init()1754if not self._is_localvalue:1755setattr(self._obj, self.attrname, odict)1756if self._is_index:1757self.reset_index()17581759def is_modified(self):1760# if self._is_child1761#is_modified = self.get_value().is_modified()1762# print 'is_modified', self.attrname, is_modified17631764childobjs = self.get_value()17651766#obj = self.get_obj()1767# print 'init_postload_internal',self.attrname,obj,obj.ident1768for _id in self.get_obj().get_ids():1769# print ' call init_postload_internal of',childobjs[_id].ident1770if childobjs[_id].is_modified():1771return True17721773def set_modified(self, is_modified):1774childobjs = self.get_value()17751776obj = self.get_obj()1777# print 'init_postload_internal',self.attrname,obj,obj.ident1778for _id in self.get_obj().get_ids():1779# print ' call init_postload_internal of',childobjs[_id].ident1780childobjs[_id].set_modified(is_modified)17811782def init_postload_external(self):1783# if self._is_child:1784# restore normally1785AttrConf.init_postload_external(self)1786childobjs = self.get_value()17871788for _id in self.get_obj().get_ids():1789childobjs[_id].init_postload_external()17901791# def get_name(self):1792# return self.'Table ID for '+self._tab.get_name()1793#1794# def get_info(self):1795# return 'ID for Table:\n'+self._tab.get_info()179617971798class Attrsman:1799"""1800Manages all attributes of an object18011802if argument obj is specified with an instance1803then attributes are stored under this instance.1804The values of attrname is then directly accessible with18051806obj.attrname18071808If nothing is specified, then column attribute will be stored under1809the respective config instance of this attrsman (self).1810The values of attrname is then directly accessible with18111812self.attrname.value1813"""18141815def __init__(self, obj, attrname='attrsman', is_plugin=False):18161817if obj is None:1818# this means that column data will be stored1819# in value attribute of attrconfigs1820obj = self1821self._is_localvalue = True1822else:1823# this means that column data will be stored under obj1824self._is_localvalue = False18251826self._obj = obj # managed object1827self._attrconfigs = [] # managed attribute config instances1828self.attrname = attrname # the manager's attribute name in the obj instance18291830self._attrs_nosave = set(ATTRS_NOSAVE)18311832# groupes of attributes1833# key=groupname, value = list of attribute config instances1834self._groups = {}18351836self.init_plugin(is_plugin)18371838def init_plugin(self, is_plugin):1839if is_plugin:1840self.plugin = Plugin(self)1841else:1842self.plugin = None18431844def enable_plugin(self, is_enabled=True):1845if self.plugin is not None:1846self.plugin.enable(is_enabled)18471848def is_localvalue(self):1849return self._is_localvalue18501851def has_attrname(self, attrname):1852# attention this is a trick, exploiting the fact that the1853# attribute object with all the attr info is an attribute1854# of the attr manager (=self)1855return hasattr(self, attrname)18561857def is_modified(self):1858for attrconf in self._attrconfigs:1859# TODO: not very clean1860if hasattr(attrconf, 'is_child'):1861if attrconf.is_child():1862if attrconf.is_modified():1863return True1864else:1865if attrconf.is_modified():1866return True18671868return False18691870def set_modified(self, is_modified=True):1871for attrconf in self._attrconfigs:1872attrconf.set_modified(is_modified)18731874def get_modified(self):1875# returns a list of modified attributes1876modified = []1877for attrconf in self._attrconfigs:1878if attrconf.is_modified():1879modified.append(attrconf)1880return modified18811882def __getitem__(self, attrname):1883return getattr(self, attrname).get_value()18841885def get_config(self, attrname):1886return getattr(self, attrname) # a bit risky18871888def get_configs(self, is_all=False, structs=None, filtergroupnames=None, is_private=False):1889# print 'get_configs',self,self._obj.ident,structs,filtergroupnames,len(self._attrconfigs)1890if is_all:1891return self._attrconfigs1892else:1893attrconfigs = []1894for attrconf in self._attrconfigs:1895# print ' found',attrconf.attrname,attrconf.struct,'groupnames',attrconf.groupnames1896is_check = True1897if (structs is not None):1898if (attrconf.struct not in structs):1899is_check = False19001901if is_check:1902# print ' **is_check',is_check1903if len(attrconf.groupnames) > 0:1904if ('_private' not in attrconf.groupnames) | is_private:1905# print ' not private'1906if filtergroupnames is not None:1907# print ' apply filtergroupnames',filtergroupnames,attrconf.groupnames1908if not set(filtergroupnames).isdisjoint(attrconf.groupnames):1909# print ' append',attrconf.attrname1910attrconfigs.append(attrconf)1911else:1912# print ' no filtergroupnames'1913attrconfigs.append(attrconf)1914else:1915if filtergroupnames is None:1916attrconfigs.append(attrconf)19171918return attrconfigs19191920# def get_colconfigs(self, is_all = False):1921# return []19221923def get_obj(self):1924return self._obj19251926def add(self, attrconf, is_overwrite=False, is_prepend=False):1927"""1928Add a one or several new attributes to be managed.1929kwargs has attribute name as key and Attribute configuration object1930as value.1931"""19321933attrname = attrconf.attrname1934# print '\n\nAttrsman.add',self.get_obj().ident,'add',attrname,self.has_attrname(attrname)1935# dir(self._obj)1936if (not self.has_attrname(attrname)) | is_overwrite:1937attrconf.set_obj(self._obj)1938attrconf.set_manager(self)19391940# set configuration object as attribute of AttrManager1941setattr(self, attrname, attrconf)19421943# append also to the list of managed objects1944if is_prepend:1945self._attrconfigs.insert(0, attrconf)1946else:1947self._attrconfigs.append(attrconf)19481949# insert in groups1950self.insert_groupnames(attrconf)19511952if self.plugin:1953self.plugin.exec_events_attr(EVTADD, attrconf)19541955# return default value as attribute of managed object1956if (attrconf.struct in STRUCTS_SCALAR) & (attrconf.is_returnval()): # == 'scalar':1957return attrconf.get_init()1958else:1959return None # table configs do their own init19601961else:1962# print ' attribute with this name already exists',attrname,type(attrconf)1963# TODO: here we could do some intelligent updating1964del attrconf1965attrconf = getattr(self, attrname)1966# print ' existing',attrconf,type(attrconf)1967if (attrconf.struct in STRUCTS_SCALAR) & (attrconf.is_returnval()): # == 'scalar':1968return attrconf.get_value()1969else:1970return None # table configs do their own init19711972def do_not_save_attr(self, attrname):1973self._attrs_nosave.add(attrname)19741975def do_save_attr(self, attrname):1976if attrname in self._attrs_nosave:1977self._attrs_nosave.remove(attrname)19781979def do_not_save_attrs(self, attrnames):1980self._attrs_nosave.update(attrnames)19811982def insert_groupnames(self, attrconf):1983if len(attrconf.groupnames) > 0:1984for groupname in attrconf.groupnames:19851986if not self._groups.has_key(groupname):1987self._groups[groupname] = []19881989if attrconf not in self._groups[groupname]:1990self._groups[groupname].append(attrconf)19911992def del_groupname(self, attrconf):1993if len(attrconf.groupnames) > 0:1994for groupname in self._groups.keys():1995attrconfigs = self._groups[groupname]1996if attrconf in attrconfigs:1997if groupname not in attrconf.groupnames:1998attrconfigs.remove(attrconf)19992000def get_groups(self):2001return self._groups20022003def get_groupnames(self):2004return self._groups.keys()20052006def has_group(self, groupname):2007return self._groups.has_key(groupname)20082009def get_group(self, name):2010"""2011Returns a list with attributes that belong to that group name.2012"""2013# print 'get_group self._groups=\n',self._groups.keys()2014return self._groups.get(name, [])20152016def get_group_attrs(self, name):2017"""2018Returns a dictionary with all attributes of a group.2019Key is attribute name and value is attribute value.2020"""2021# print 'get_group_attrs', self._groups2022attrs = OrderedDict()2023if not self._groups.has_key(name):2024return attrs2025for attrconf in self._groups[name]:2026# print ' attrconf.attrname',attrconf.attrname2027attrs[attrconf.attrname] = getattr(self._obj, attrconf.attrname)2028# print ' attrs',attrs2029return attrs20302031def write_csv(self, fd, sep=',',2032show_parentesis=False, attrconfigs=None,2033groupnames=None,2034is_export_not_save=True):2035# print 'Attrsman.write_csv attrconfigs'#,attrconfigs,'groupnames',groupnames,2036if attrconfigs is None:2037attrconfigs = self.get_configs(is_all=False, structs=STRUCTS_SCALAR, filtergroupnames=groupnames)20382039for attrconf in attrconfigs:2040# print ' attrconfig', attrconf.attrname,attrconf.struct,attrconf.metatype2041if (attrconf.is_save() | is_export_not_save) & (attrconf.struct in STRUCTS_SCALAR):2042mt = attrconf.metatype20432044if mt == 'id':2045fd.write('%s %s%s%s\n' % (attrconf.attrname, attrconf.format_unit(show_parentesis),2046sep, attrconf.get_linktab().format_ids([attrconf.get_value()])))2047else:2048fd.write('%s %s%s%s\n' % (attrconf.attrname, attrconf.format_unit(2049show_parentesis), sep, attrconf.format_value()))20502051def print_attrs(self, show_unit=True, show_parentesis=False, attrconfigs=None):2052print 'Attributes of', self._obj._name, 'ident_abs=', self._obj.get_ident_abs()2053if attrconfigs is None:2054attrconfigs = self.get_configs(structs=STRUCTS_SCALAR)20552056# for attrconf in attrconfigs:2057# print ' %s =\t %s'%(attrconf.attrname, attrconf.format_value(show_unit=True))20582059def save_values(self, state):2060"""2061Called by the managed object during save to save the2062attribute values.2063"""2064for attrconfig in self.get_configs():2065attrconfig.save_value(state)20662067def delete(self, attrname):2068"""2069Delete attribute with respective name2070"""2071# print '.__delitem__','attrname=',attrname20722073# if hasattr(self,attrname):2074attrconf = getattr(self, attrname)20752076if attrconf in self._attrconfigs:2077if self.plugin:2078self.plugin.exec_events_attr(EVTDEL, attrconf)20792080for groupname in attrconf.groupnames:2081self._groups[groupname].remove(attrconf)20822083self._attrconfigs.remove(attrconf)2084attrconf.predelete() # this will remove also the value attribute20852086#attrname = attrconf.attrname2087del self.__dict__[attrname] # delete config2088return True20892090return False # attribute not managed2091# return False # attribute not existant20922093def __getstate__(self):2094# if hasattr(self,'attrname'):2095# print 'Attrsman.__getstate__ of',self.attrname,' of obj=',self._obj.ident,'id',id(self),'id obj',id(self._obj)2096#2097# else:2098# print 'WARNING in Attrsman.__getstate__',self,'attrname missing','id',id(self),'id obj',id(self._obj)20992100if not hasattr(self, '_obj'):2101print 'WARNING: unknown obj in attrman', self, type(self)2102# print ' dir',dir(self)2103# if hasattr(self,'attrname'):2104# print ' No attrman but attribute',self.attrname2105# for attrconf in self.get_configs(is_all=True):2106# print ' attrname=',attrconf.attrname2107return {}21082109# if not hasattr(self,'_attrs_nosave'):2110# print 'WARNING: in __getstate__ of',self.attrname#,'obj',self._obj,'has no attr _attrs_nosave'2111# #self.print_attrs()2112# print 'dict=\n',self.__dict__21132114# print ' self.__dict__=\n',self.__dict__.keys()21152116state = {}2117for attr in self.__dict__.keys():2118# print ' attr',attr,self.__dict__[attr]2119# TODO: optimize and put this at the end2120if attr == 'plugin':2121plugin = self.__dict__[attr]2122if plugin is not None:2123state[attr] = True2124else:2125state[attr] = False21262127elif attr == '_attrconfigs':2128attrconfigs_save = []2129for attrconfig in self._attrconfigs:21302131if attrconfig.is_save():2132# print ' save',attrconfig.attrname2133# if attrconfig.struct == 'array':2134# print ' size =',len(self)2135attrconfigs_save.append(attrconfig)2136state[attr] = attrconfigs_save21372138elif attr not in self._attrs_nosave:2139state[attr] = self.__dict__[attr]21402141# print ' _attrs_nosave=', self._attrs_nosave2142# print ' state=', state2143return state21442145def __setstate__(self, state):2146# print '__setstate__',self21472148# this is always required, but will not be saved2149# self.plugins={}21502151for attr in state.keys():2152# print ' set state',attr2153# plugin set in init_postload_internal2154# if attr=='plugin':2155# if state[attr]==True:2156# self.__dict__[attr] = Plugin(self)2157# else:2158# self.__dict__[attr]= None2159# else:2160self.__dict__[attr] = state[attr]21612162def init_postload_internal(self, obj):2163"""2164Called after set state.2165Link internal states.2166"""2167# print 'Attrsman.init_postload_internal of obj:',obj.ident21682169if not hasattr(self, '_attrs_nosave'):2170self._attrs_nosave = set(ATTRS_NOSAVE)21712172# if not hasattr(self,'_attrs_nosave'):2173# print 'WARNING: in init_postload_internal of',self.attrname,'obj',obj,'has no attr _attrs_nosave'21742175self._obj = obj2176self.init_plugin(self.plugin)2177for attrconfig in self.get_configs(is_all=True):2178# print ' call init_postload_internal of',attrconfig.attrname2179attrconfig.init_postload_internal(self, obj)21802181def init_postload_external(self):2182"""2183Called after set state.2184Link external states.2185"""2186# print 'Attrsman.init_postload_external',self._obj.get_ident()21872188for attrconfig in self.get_configs(is_all=True):2189# print ' call',attrconfig.attrname,attrconfig.metatype2190attrconfig.init_postload_external()219121922193class Tabman(Attrsman):2194"""2195Manages all table attributes of an object.21962197if argument obj is specified with an instance2198then column attributes are stored under this instance.2199The values of attrname is then directly accessible with22002201obj.attrname22022203If nothing is specified, then column attribute will be stored under2204the respective config instance of this tab man (self).2205The values of attrname is then directly accessible with22062207self.attrname.value22082209"""22102211def __init__(self, obj=None, **kwargs):2212Attrsman.__init__(self, obj, **kwargs)2213self._colconfigs = []2214self._ids = []22152216def add_col(self, attrconf):2217# print 'add_col',attrconf.attrname,attrconf.is_index()2218attrname = attrconf.attrname2219if not self.has_attrname(attrname):2220Attrsman.add(self, attrconf) # insert in common attrs database2221self._colconfigs.append(attrconf)2222# returns initial array and also create local array if self._is_localvalue == True2223return attrconf.get_init()2224else:2225return getattr(self, attrname).get_value()22262227def delete(self, attrname):2228"""2229Delete attribute with respective name2230"""2231# print '.__delitem__','attrname=',attrname22322233if hasattr(self, attrname):2234attrconf = getattr(self, attrname)2235if self.plugin:2236self.plugin.exec_events_attr(EVTDEL, attrconf)2237if Attrsman.delete(self, attrname):2238if attrconf in self._colconfigs:2239self._colconfigs.remove(attrconf)22402241def get_colconfigs(self, is_all=False, filtergroupnames=None):2242if is_all:2243return self._colconfigs2244else:2245colconfigs = []2246if filtergroupnames is not None:2247filtergroupnameset = set(filtergroupnames)2248for colconfig in self._colconfigs:2249if len(colconfig.groupnames) > 0:2250if '_private' not in colconfig.groupnames:2251if filtergroupnames is not None:2252if not filtergroupnameset.isdisjoint(colconfig.groupnames):2253colconfigs.append(colconfig)2254else:2255colconfigs.append(colconfig)22562257else:2258if filtergroupnames is None:2259colconfigs.append(colconfig)22602261return colconfigs22622263def get_ids(self):2264return self._ids22652266def __len__(self):2267"""2268Determine current array length (same for all arrays)2269"""22702271return len(self._ids)22722273def __contains__(self, _id):2274return _id in self._ids22752276def select_ids(self, mask):22772278ids_mask = []2279i = 02280for _id in self.get_ids():2281if mask[i]:2282ids_mask.append(_id)2283i += 122842285return ids_mask22862287def suggest_id(self, is_zeroid=False):2288"""2289Returns a an availlable id.22902291Options:2292is_zeroid=True allows id to be zero.22932294"""2295if is_zeroid:2296id0 = 02297else:2298id0 = 122992300id_set = set(self.get_ids())2301if len(id_set) == 0:2302id_max = 02303else:2304id_max = max(id_set)2305# print 'suggest_id',id0,2306return list(id_set.symmetric_difference(xrange(id0, id_max+id0+1)))[0]23072308def suggest_ids(self, n, is_zeroid=False):2309"""2310Returns a list of n availlable ids.2311It returns even a list for n=1.23122313Options:2314is_zeroid=True allows id to be zero.2315"""2316if is_zeroid:2317id0 = 02318else:2319id0 = 12320id_set = set(self.get_ids())2321if len(id_set) == 0:2322id_max = 02323else:2324id_max = max(id_set)23252326return list(id_set.symmetric_difference(xrange(id0, id_max+id0+n)))[:n]23272328def add_rows(self, n=None, ids=[], **attrs):2329if n is not None:2330ids = self.suggest_ids(n)2331elif len(ids) == 0:2332# get number of rows from any valye vector provided2333ids = self.suggest_ids(len(attrs.values()[0]))2334else:2335# ids already given , no ids to create2336pass23372338self._ids += ids2339# print 'add_rows ids', ids2340for colconfig in self._colconfigs:2341colconfig.add(ids, values=attrs.get(colconfig.attrname, None))2342if self.plugin:2343self.plugin.exec_events_ids(EVTADDITEM, ids)2344return ids23452346def add_row(self, _id=None, **attrs):2347if _id is None:2348_id = self.suggest_id()2349self._ids += [_id, ]2350for colconfig in self._colconfigs:2351colconfig.add(_id, values=attrs.get(colconfig.attrname, None))2352if self.plugin:2353self.plugin.exec_events_ids(EVTADDITEM, [_id])2354return _id23552356def set_row(self, _id, **attrs):2357for colconfig in self._colconfigs:2358colconfig.set(_id, values=attrs.get(colconfig.attrname, None))2359if self.plugin:2360self.plugin.exec_events_ids(EVTSETITEM, [_id])23612362def set_rows(self, ids, **attrs):23632364# print 'add_rows ids', ids2365for colconfig in self._colconfigs:2366colconfig.set(ids, values=attrs.get(colconfig.attrname, None))2367if self.plugin:2368self.plugin.exec_events_ids(SETSETITEM, ids)23692370def get_row(self, _id):2371attrvalues = {}2372if self.plugin:2373self.plugin.exec_events_ids(EVTGETITEM, [_id])2374for attrconfig in self._colconfigs:2375attrvalues[attrconfig.attrname] = attrconfig[_id]23762377return attrvalues23782379def del_rows(self, ids):2380if self.plugin:2381self.plugin.exec_events_ids(EVTDELITEM, ids)2382for colconfig in self._colconfigs:2383del colconfig[ids]23842385for _id in ids:2386self._ids.remove(_id)23872388def del_row(self, _id):2389if self.plugin:2390self.plugin.exec_events_ids(EVTDELITEM, [_id])2391for colconfig in self._colconfigs:2392del colconfig[_id]2393self._ids.remove(_id)23942395def __delitem__(self, ids):2396"""2397remove rows correspondent to the given ids from all array and dict2398attributes2399"""2400if hasattr(ids, '__iter__'):2401self.del_rows(ids)2402else:2403self.del_row(ids)24042405def print_attrs(self, ids=None, **kwargs):2406# print 'Attributes of',self._obj._name,'(ident=%s)'%self._obj.ident2407Attrsman.print_attrs(self, attrconfigs=self.get_configs(structs=['scalar']), **kwargs)2408# print ' ids=',self._ids2409if ids is None:2410ids = self.get_ids()24112412for _id in ids:2413for attrconf in self.get_configs(structs=STRUCTS_COL):2414print ' %s[%d] =\t %s' % (attrconf.attrname, _id, attrconf.format_value(_id, show_unit=True))24152416def write_csv(self, fd, sep=',', ids=None,2417attrconfigs=None,2418groupnames=None,2419show_parentesis=True,2420is_export_not_save=True, # export attr, also non save2421name_id='ID',2422):2423# if attrconfigs is None:2424# attrconfigs = self.get_configs()2425# print 'Tabman.write_csv attrconfigs is_export_not_save',is_export_not_save24262427Attrsman.write_csv(self, fd, sep=sep,2428show_parentesis=show_parentesis,2429groupnames=groupnames,2430attrconfigs=attrconfigs,2431#is_export_private = False,2432is_export_not_save=is_export_not_save, # export attr, also non save2433)2434# fd.write('\n')2435# for attrconf in attrconfigs:2436# #print ' %s =\t %s'%(attrconf.attrname, attrconf.format_value(show_unit=True))2437# fd.write( '%s %s%s%s\n'%(attrconf.attrname,format_unit(show_parentesis), sep, attrconf.format_value()))24382439if ids is None:2440ids = self.get_ids()24412442if groupnames is not None:2443#attrconfigs = self.get_group(groupname)2444attrconfigs = self.get_configs(is_all=False, filtergroupnames=groupnames)2445is_exportall = False24462447elif attrconfigs is None:2448attrconfigs = self.get_colconfigs(is_all=False)2449#is_exportall = False24502451# check if attributes are all column attribute and indicted for save2452attrconfigs_checked = []2453for attrconf in attrconfigs:2454if (attrconf.is_save() | is_export_not_save) & (attrconf.struct in STRUCTS_COL):24552456attrconfigs_checked.append(attrconf)24572458# first table row2459row = name_id2460for attrconf in attrconfigs_checked:2461# print ' attrconfig', attrconf.attrname,attrconf.metatype2462row += sep+self._clean_csv(attrconf.format_symbol(show_parentesis=show_parentesis), sep)2463fd.write(row+'\n')24642465# rest2466for _id in ids:2467row = str(_id)2468row = self._clean_csv(row, sep)2469for attrconf in attrconfigs:2470mt = attrconf.metatype2471# print ' attrconf,',attrconf.attrname,mt,attrconf[_id]2472if mt == 'id':2473# print ' ',2474row += sep+self._clean_csv(attrconf.get_linktab().format_ids([attrconf[_id]]), sep)2475else:2476row += sep+self._clean_csv('%s' % (attrconf.format_value(_id, show_unit=False)), sep)24772478# make sure there is no CR in the row!!2479# print row2480fd.write(row+'\n')248124822483class BaseObjman:2484"""2485Object management base methods to be inherited by all object managers.2486"""24872488def __init__(self, ident, is_plugin=False, **kwargs):2489# print 'BaseObjman.__init__',ident#,kwargs2490self._init_objman(ident, **kwargs)2491self.set_attrsman(Attrsman(self, is_plugin=is_plugin))2492# print 'BaseObjman.__init__',self.format_ident(),'parent=',self.parent2493self._init_attributes()2494self._init_constants()24952496def set_attrsman(self, attrsman):2497self._attrsman = attrsman2498return attrsman24992500def _init_objman(self, ident='no_ident', parent=None, name=None,2501managertype='basic', info=None, logger=None,2502xmltag=None, version=0.0):2503# print 'BaseObjman._init_objman',ident,logger,parent2504self.managertype = managertype2505self.ident = ident2506self.set_version(version)2507self.set_logger(logger)25082509#self._is_root = False2510self.parent = parent2511self.childs = {} # dict with attrname as key and child instance as value25122513self._info = info25142515self._is_saved = False25162517if name is None:2518self._name = self.format_ident()2519else:2520self._name = name25212522self.set_xmltag(xmltag)25232524# print ' self.parent',self.parent2525# must be called explicitely during __init__2526# self._init_attributes()2527# self._init_constants()25282529def _init_attributes(self):2530"""2531This is the place to add all attributes.2532This method will be called to initialize2533and after loading a saved object.2534Use this method also to update a version.2535"""2536pass25372538def _init_constants(self):2539"""2540This is the place to init any costants that are outside the management.2541Constants are not saved.2542This method will be called to initialize and after loading a saved object.2543"""2544pass25452546def set_version(self, version):25472548self._version = version25492550def get_version(self):2551if hasattr(self, '_version'):2552return self._version2553else:2554# for compatibility2555return 0.025562557# def _upgrade_version(self):2558# pass25592560# def _init_xml(self,xmltag=None):2561# if xmltag is not None:2562# self.xmltag = xmltag2563# else:2564# self.xmltag = self.get_ident()25652566def reset(self):2567"""2568Resets all attributes to default values2569"""2570# print 'reset'2571for attrconfig in self.get_attrsman().get_configs(is_all=True):2572# print ' reset',attrconfig.attrname2573attrconfig.reset()25742575def clear(self):2576"""2577Clear tables and reset scalars.2578"""2579for attrconfig in self.get_attrsman().get_configs(is_all=True):2580attrconfig.clear()25812582self._init_constants()25832584def unplug(self):2585if self.plugin:2586self.plugin.unplug()25872588def set_xmltag(self, xmltag, xmlsep=' '):2589self.xmltag = xmltag2590self.xmlsep = xmlsep25912592def write_xml(self, fd, ident):2593if self.xmltag is not None:2594# figure out scalar attributes and child objects2595attrconfigs = []2596objconfigs = []2597for attrconfig in self.get_attrsman().get_configs(structs=STRUCTS_SCALAR):2598if (attrconfig.metatype == 'obj'): # better use self.childs2599if (attrconfig.get_value().xmltag is not None) & attrconfig.is_child():2600objconfigs.append(attrconfig)2601elif attrconfig.xmltag is not None:2602attrconfigs.append(attrconfig)26032604# start writing2605if len(attrconfigs) > 0:2606# there are scalar attributes2607fd.write(xm.start(self.xmltag, ident))2608for attrconfig in attrconfigs:2609attrconfig.write_xml(fd)26102611# are there child objects to write2612if len(objconfigs) > 0:2613fd.write(xm.stop())2614for attrconfig in objconfigs:2615attrconfig.get_value().write_xml(fd, ident+2)2616fd.write(xm.end(self.xmltag, ident))2617else:2618fd.write(xm.stopit())2619else:2620# no scalars2621fd.write(xm.begin(self.xmltag, ident))2622if len(objconfigs) > 0:2623for attrconfig in objconfigs:2624attrconfig.get_value().write_xml(fd, ident+2)2625fd.write(xm.end(self.xmltag, ident))26262627def get_logger(self):2628# print 'get_logger',self.ident,self._logger,self.parent2629if self._logger is not None:2630return self._logger2631else:2632return self.parent.get_logger()26332634def set_logger(self, logger):2635# print 'set_logger',self.ident,logger2636self._logger = logger26372638def __repr__(self):2639# return '|'+self._name+'|'2640return self.format_ident()26412642def is_modified(self):2643return self._attrsman.is_modified()26442645def set_modified(self, is_modified=True):2646self._attrsman.set_modified(is_modified)26472648def get_name(self):2649return self._name26502651def get_info(self):2652if self._info is None:2653return self.__doc__2654else:2655return self._info26562657def get_ident(self):2658return self.ident26592660def _format_ident(self, ident):2661if hasattr(ident, '__iter__'):2662return str(ident[0])+'#'+str(ident[1])2663else:2664return str(ident)26652666def format_ident(self):2667return self._format_ident(self.ident)26682669def format_ident_abs(self):2670s = ''2671# print 'format_ident_abs',self.get_ident_abs()2672for ident in self.get_ident_abs():2673s += self._format_ident(ident)+'.'2674return s[:-1]26752676def export_csv(self, filepath, sep=',',2677attrconfigs=None, groupnames=None,2678is_header=True, is_ident=False, is_timestamp=True,2679show_parentesis=True):2680"""2681Export scalars to file feed in csv format.2682"""2683print 'BaseObjman.export_csv', filepath, "*"+sep+"*", 'attrconfigs', attrconfigs, self.get_attrsman()2684fd = open(filepath, 'w')26852686# header2687if is_header:26882689row = self._clean_csv(self.get_name(), sep)2690if is_ident:2691row += sep+'(ident=%s)' % self.format_ident_abs()2692fd.write(row+'\n')2693if is_timestamp:2694now = datetime.now()2695fd.write(self._clean_csv(now.isoformat(), sep)+'\n')2696fd.write('\n\n')26972698self.get_attrsman().write_csv(fd, sep=sep,2699show_parentesis=show_parentesis, groupnames=groupnames,2700attrconfigs=attrconfigs)27012702fd.close()27032704def _clean_csv(self, row, sep):2705row = row.replace('\n', ' ')2706#row=row.replace('\b',' ')2707row = row.replace('\r', ' ')2708#row=row.replace('\f',' ')2709#row=row.replace('\newline',' ')2710row = row.replace(sep, ' ')2711return row27122713def get_root(self):2714# if hasattr(self,'_is_root'):2715# print 'get_root',self.ident,'is_root',self._is_root2716# if self._is_root:2717# return self27182719if self.parent is not None:2720return self.parent.get_root()2721else:2722return self27232724def get_ident_abs(self):2725"""2726Returns absolute identity.2727This is the ident of this object in the global tree of objects.2728If there is a parent objecty it must also be managed by the2729object manager.2730"""2731# print 'obj.get_ident_abs',self.ident,self.parent, type(self.parent)2732# if hasattr(self,'_is_root'):2733# print 'get_ident_abs',self.ident,'is_root',self._is_root2734# if self._is_root:2735# return (self.get_ident(),)# always return tuple27362737if self.parent is not None:2738return self.parent.get_ident_abs()+(self.ident,)2739else:2740return (self.get_ident(),) # always return tuple27412742def get_obj_from_ident(self, ident_abs):2743# print 'get_obj_from_ident',self.ident,ident_abs2744if len(ident_abs) == 1:2745# arrived at the last element2746# check if it corresponds to the present object2747if ident_abs[0] == self.ident:2748return self2749else:2750return None # could throw an error2751else:2752return self.get_childobj(ident_abs[1]).get_obj_from_ident(ident_abs[1:])27532754# this is an attemt to restore objects from2755# root objects without childs2756# def search_ident_abs(self, childobj):2757# """2758# Returns root and absolute ident for the found root.2759# """2760# #if hasattr(self,'_is_root'):2761# # print 'get_root',self.ident,'is_root',self._is_root2762# # if self._is_root:2763# # return self2764#2765# if self.parent is not None:2766# if self.parent.childs.has_key(childobj.ident)2767# return self.parent.get_root()2768# else:2769# return self27702771# def search_obj_from_ident(self, ident_abs, obj_init):2772#2773# #print 'get_obj_from_ident',self.ident,ident_abs2774# if len(ident_abs)==1:2775# # arrived at the last element2776# # check if it corresponds to the present object2777# if ident_abs[0] == self.ident:2778# return self2779# else:2780# return None # could throw an error2781# else:2782# return self.get_childobj(ident_abs[1]).get_obj_from_ident(ident_abs[1:])27832784def get_childobj(self, attrname):2785"""2786Return child instance2787"""2788if self.childs.has_key(attrname):2789config = self.childs[attrname]2790return config.get_value()2791else:2792return BaseObjman(self)27932794def set_child(self, childconfig):2795"""2796Set child childconfig2797"""2798self.childs[childconfig.attrname] = childconfig27992800def del_child(self, attrname):2801"""2802Return child instance2803"""2804del self.childs[attrname]28052806def get_parent(self):2807return self.parent28082809# def reset_parent(self, parent):2810# self.parent=parent28112812# def set_attrsman(self, attrsman):2813# # for quicker acces and because it is only on2814# # the attribute management is public and also directly accessible2815# #setattr(self, attrname,Attrsman(self))# attribute management2816# self._attrsman = attrsman2817# #return attrsman28182819def get_attrsman(self):2820return self._attrsman28212822def _getstate_specific(self, state):2823"""2824Called by __getstate__ to add/change specific states,2825before returning states.2826To be overridden.2827"""2828pass28292830def __getstate__(self):2831# print 'BaseObjman.__getstate__',self.ident,self._is_saved2832# print ' self.__dict__=\n',self.__dict__.keys()2833state = {}2834# if not self._is_saved:28352836# if self._is_saved:2837# # this message indicates a loop!!2838# print 'WARNING in __getstate__: object already saved',self.format_ident_abs()28392840# print ' save standart values'2841for attr in ATTRS_SAVE:2842if hasattr(self, attr):2843state[attr] = getattr(self, attr)28442845# print ' save all scalar stuctured attributes'2846# attrsman knows which and how2847# self._attrsman.save_values(state)2848#2849# values of configured attributes are not saved here2850# values are now ALWAYS stored in the value attribute of the2851# attrconfig and reset in main obj28522853# print ' save also attrsman'2854state['_attrsman'] = self._attrsman2855self._getstate_specific(state)28562857self._is_saved = True28582859# else:2860# print 'WARNING in __getstate__: object %s already saved'%self.ident2861return state28622863def __setstate__(self, state):2864# print '__setstate__',self28652866# this is always required, but will not be saved2867# self.plugins={}28682869for key in state.keys():2870# print ' set state',key2871self.__dict__[key] = state[key]28722873self._is_saved = False2874# done in init2_config...2875# set default values for all states tha have not been saved2876# for attr in self._config.keys():2877# if (not self._config[attr]['save']) & (not hasattr(self,attr)):2878# print ' config attr',attr2879# self.config(attr,**self._config[attr])28802881# set other states2882# self._setstate(state)28832884def init_postload_internal(self, parent):2885"""2886Called after set state.2887Link internal states and call constant settings.2888"""2889print 'BaseObjman.init_postload_internal', self.ident, 'parent:'2890# if parent is not None:2891# print parent.ident2892# else:2893# print 'ROOT'2894self.parent = parent2895self.childs = {}2896self._attrsman.init_postload_internal(self)28972898def init_postload_external(self):2899"""2900Called after set state.2901Link internal states.2902"""29032904#self._is_root = is_root2905# print 'init_postload_external',self.ident#,self._is_root2906# set default logger2907self.set_logger(Logger(self))2908# for child in self.childs.values():2909# child.reset_parent(self)2910self._attrsman.init_postload_external()2911self._init_attributes()2912self._init_constants()291329142915class TableMixin(BaseObjman):29162917def format_ident_row(self, _id):2918# print 'format_ident_row',_id2919return self.format_ident()+'['+str(_id)+']'29202921def format_ident_row_abs(self, _id):2922return self.format_ident_abs()+'['+str(_id)+']'29232924def get_obj_from_ident(self, ident_abs):2925# print 'get_obj_from_ident',self.ident,ident_abs,type(ident_abs)2926if len(ident_abs) == 1:2927# arrived at the last element2928# check if it corresponds to the present object2929ident_check = ident_abs[0]29302931# now 2 things can happen:2932# 1.) the ident is a simple string identical to ident of the object2933# in this case, return the whole object2934# 2.) ident is a tuple with string and id2935# in this case return object and ID2936# if hasattr(ident_check, '__iter__'):2937# #if (ident_check[0] == self.ident)&(ident_check[1] in self._ids):2938# if ident_check[1] in self._ids:2939# return (self, ident_check[1])2940# else:2941# return None # could throw an error2942# else:2943if ident_check == self.ident:2944return self2945else:2946childobj = self.get_childobj(ident_abs[1])2947return childobj.get_obj_from_ident(ident_abs[1:])29482949def get_childobj(self, ident):2950"""2951Return child instance.2952This is any object with ident2953"""2954if hasattr(ident, '__iter__'):2955# access of ObjsConf configured child2956# get object from column attrname2957attrname, _id = ident2958config = self.childs[attrname]2959return config[_id] # config.get_valueobj(_id)2960else:2961# access of ObjConf configured child2962# get object from attrname2963config = self.childs[ident]2964return config.get_value()29652966def __getstate__(self):2967# print '__getstate__',self.ident,self._is_saved2968# print ' self.__dict__=\n',self.__dict__.keys()2969state = {}2970if 1: # not self._is_saved:29712972# print ' save standart values'2973for attr in ATTRS_SAVE+ATTRS_SAVE_TABLE:2974if attr == 'plugin':2975plugin = self.__dict__[attr]2976if plugin is not None:2977state[attr] = True2978else:2979state[attr] = False29802981elif hasattr(self, attr):2982state[attr] = getattr(self, attr)29832984# save managed attributes !!!2985for attrconfig in self.get_configs(is_all=True):2986state[attrconfig.attrname] = attrconfig29872988# print ' save all scalar stuctured attributes'2989# attrsman knows which and how2990# self.save_values(state)29912992# print ' save also attrsman'2993#state['attrsman'] = self._attrsman2994self._is_saved = True29952996else:2997print 'WARNING in __getstate__: object %s already saved' % self.ident2998return state29993000def __setstate__(self, state):3001# print '__setstate__',self.ident30023003# this is always required, but will not be saved3004self.plugins = {}30053006for attr in state.keys():3007# print ' set state',key3008if attr == 'plugin':3009if state[attr] == True:3010self.__dict__[attr] = Plugin(self)3011else:3012self.__dict__[attr] = None3013else:3014self.__dict__[attr] = state[attr]30153016self._is_saved = False3017# done in init2_config...3018# set default values for all states tha have not been saved3019# for attr in self._config.keys():3020# if (not self._config[attr]['save']) & (not hasattr(self,attr)):3021# print ' config attr',attr3022# self.config(attr,**self._config[attr])30233024# set other states3025# self._setstate(state)30263027def init_postload_internal(self, parent):3028"""3029Called after set state.3030Link internal states.3031"""3032# print 'TableObjman.init_postload_internal',self.ident,'parent:',3033# if parent is not None:3034# print parent.ident3035# else:3036# print 'ROOT'30373038if not hasattr(self, '_attrs_nosave'):3039self._attrs_nosave = set(ATTRS_NOSAVE)30403041self.parent = parent3042self.childs = {}3043self.set_attrsman(self)3044Attrsman.init_postload_internal(self, self)30453046self._is_saved = False30473048def init_postload_external(self):3049"""3050Called after set state.3051Link internal states.3052"""3053Attrsman.init_postload_external(self)3054# no: BaseObjman.init_postload_external(self)3055self._init_attributes()3056self._init_constants()30573058def export_csv(self, filepath, sep=',',3059ids=None, attrconfigs=None, groupnames=None,3060is_header=True, is_ident=False, is_timestamp=True,3061show_parentesis=True, name_id='ID'):3062"""3063Export scalars to file feed in csv format.3064"""3065print 'TableMixin.export_csv', filepath, "*"+sep+"*" # ,'attrconfigs',attrconfigs,self.get_attrsman()3066fd = open(filepath, 'w')30673068# header3069if is_header:30703071row = self._clean_csv(self.get_name(), sep)3072if is_ident:3073row += sep+'(ident=%s)' % self.format_ident_abs()3074fd.write(row+'\n')3075if is_timestamp:3076now = datetime.now()3077fd.write(self._clean_csv(now.isoformat(), sep)+'\n')3078fd.write('\n\n')30793080self.get_attrsman().write_csv(fd, sep=sep, ids=ids,3081show_parentesis=show_parentesis, groupnames=groupnames,3082attrconfigs=attrconfigs, name_id='ID')30833084fd.close()30853086def clear_rows(self):3087if self.plugin:3088self.plugin.exec_events_ids(EVTDELITEM, self.get_ids())3089self._ids = []3090for colconfig in self.get_attrsman()._colconfigs:3091# print 'ArrayObjman.clear_rows',colconfig.attrname,len(colconfig.get_value())3092colconfig.clear()3093# print ' done',len(colconfig.get_value())30943095def clear(self):3096# print 'ArrayObjman.clear',self.ident3097# clear/reset scalars3098for attrconfig in self.get_attrsman().get_configs(structs=STRUCTS_SCALAR):3099attrconfig.clear()3100self.clear_rows()3101self.set_modified()31023103def _write_xml_body(self, fd, indent, objconfigs, idcolconfig_include_tab, colconfigs,3104objcolconfigs, xmltag_item, attrconfig_id, xmltag_id, ids, ids_xml):31053106# print '_write_xml_body ident,ids',self.ident,ids3107if ids is None:3108ids = self.get_ids()31093110if ids_xml is None:3111ids_xml = ids31123113for attrconfig in objconfigs:3114attrconfig.get_value().write_xml(fd, indent+2)31153116# check if columns contain objects3117#objcolconfigs = []3118scalarcolconfigs = colconfigs3119# for attrconfig in colconfigs:3120# if attrconfig.metatype == 'obj':3121# objcolconfigs.append(attrconfig)3122# else:3123# scalarcolconfigs.append(attrconfig)31243125for _id, id_xml in zip(ids, ids_xml):3126fd.write(xm.start(xmltag_item, indent+2))31273128# print ' make tag and id',_id3129if xmltag_id == '':3130# no id tag will be written3131pass3132elif (attrconfig_id is None) & (xmltag_id is not None):3133# use specified id tag and and specified id values3134fd.write(xm.num(xmltag_id, id_xml))31353136elif (attrconfig_id is not None):3137# use id tag and values of attrconfig_id3138attrconfig_id.write_xml(fd, _id)31393140# print ' write columns',len(scalarcolconfigs)>0,len(idcolconfig_include_tab)>0,len(objcolconfigs)>03141for attrconfig in scalarcolconfigs:3142# print ' scalarcolconfig',attrconfig.attrname3143attrconfig.write_xml(fd, _id)31443145if (len(idcolconfig_include_tab) > 0) | (len(objcolconfigs) > 0):3146fd.write(xm.stop())31473148for attrconfig in idcolconfig_include_tab:3149# print ' include_tab',attrconfig.attrname3150attrconfig.write_xml(fd, _id, indent+4)31513152for attrconfig in objcolconfigs:3153# print ' objcolconfig',attrconfig.attrname3154attrconfig[_id].write_xml(fd, indent+4)3155fd.write(xm.end(xmltag_item, indent+2))3156else:3157fd.write(xm.stopit())31583159# print ' _write_xml_body: done'31603161def write_xml(self, fd, indent, xmltag_id='id', ids=None, ids_xml=None,3162is_print_begin_end=True, attrconfigs_excluded=[]):3163# print 'write_xml',self.ident#,ids3164if self.xmltag is not None:3165xmltag, xmltag_item, attrname_id = self.xmltag31663167if xmltag == '': # no begin end statements3168is_print_begin_end = False31693170if ids is not None:3171if not hasattr(ids, '__iter__'):3172ids = [ids]31733174if attrname_id == '': # no id info will be written3175attrconfig_id = None3176xmltag_id = ''31773178elif attrname_id is not None: # an attrconf for id has been defined3179attrconfig_id = getattr(self.get_attrsman(), attrname_id)3180xmltag_id = None # this will define the id tag3181else:3182attrconfig_id = None # native id will be written using xmltag_id from args31833184# print ' attrname_id,attrconfig_id',attrname_id,attrconfig_id3185# if attrconfig_id is not None:3186# print ' attrconfig_id',attrconfig_id.attrname31873188# figure out scalar attributes and child objects3189attrconfigs = []3190objconfigs = []3191colconfigs = []3192objcolconfigs = []3193idcolconfig_include_tab = []3194for attrconfig in self.get_attrsman().get_configs(is_all=True):3195# print ' check',attrconfig.attrname,attrconfig.xmltagis not None,attrconfig.is_colattr(),attrconfig.metatype3196if attrconfig == attrconfig_id:3197pass3198elif attrconfig in attrconfigs_excluded:3199pass3200elif attrconfig.is_colattr() & (attrconfig.metatype == 'obj'):3201objcolconfigs.append(attrconfig)3202elif (attrconfig.is_colattr()) & (attrconfig.metatype in ('ids', 'id')) & (attrconfig.xmltag is not None):3203if hasattr(attrconfig, "is_xml_include_tab"):3204if attrconfig.is_xml_include_tab:3205idcolconfig_include_tab.append(attrconfig)3206else:3207colconfigs.append(attrconfig)3208else:3209colconfigs.append(attrconfig)3210elif attrconfig.is_colattr() & (attrconfig.xmltag is not None):3211colconfigs.append(attrconfig)3212elif (attrconfig.metatype == 'obj'): # better use self.childs3213if (attrconfig.get_value().xmltag is not None) & attrconfig.is_child():3214objconfigs.append(attrconfig)3215elif attrconfig.xmltag is not None:3216attrconfigs.append(attrconfig)32173218# print ' attrconfigs',attrconfigs3219# print ' objconfigs',objconfigs3220# print ' idcolconfig_include_tab',idcolconfig_include_tab3221# print ' colconfigs',colconfigs3222# start writing3223if len(attrconfigs) > 0:3224# print ' there are scalar attributes'3225if is_print_begin_end:3226fd.write(xm.start(xmltag, indent))3227for attrconfig in attrconfigs:3228attrconfig.write_xml(fd)32293230# are there child objects to write3231if (len(objconfigs) > 0) | (len(colconfigs) > 0) | (len(idcolconfig_include_tab) > 0):3232fd.write(xm.stop())3233self._write_xml_body(fd, indent, objconfigs, idcolconfig_include_tab,3234colconfigs,3235objcolconfigs,3236xmltag_item, attrconfig_id,3237xmltag_id, ids, ids_xml)3238fd.write(xm.end(xmltag, indent))32393240else:3241fd.write(xm.stopit())3242else:3243# print ' no scalars'3244if is_print_begin_end:3245fd.write(xm.begin(xmltag, indent))3246self._write_xml_body(fd, indent, objconfigs, idcolconfig_include_tab,3247colconfigs,3248objcolconfigs,3249xmltag_item, attrconfig_id,3250xmltag_id, ids, ids_xml)32513252if is_print_begin_end:3253fd.write(xm.end(xmltag, indent))325432553256class TableObjman(Tabman, TableMixin):3257"""3258Table Object management manages objects with list and dict based columns.3259For faster operation use ArrayObjman in arrayman package, which requires numpy.3260"""32613262def __init__(self, ident, **kwargs):3263self._init_objman(ident, **kwargs)3264self._init_attributes()3265self._init_constants()32663267def _init_objman(self, ident, is_plugin=False, **kwargs):3268BaseObjman._init_objman(self, ident, managertype='table', **kwargs)3269Tabman.__init__(self, is_plugin=is_plugin)3270# self.set_attrsman(self)3271self.set_attrsman(self)327232733274###############################################################################3275if __name__ == '__main__':3276"""3277Test3278"""32793280pass328132823283