mirror of https://github.com/QMCPACK/qmcpack.git
1364 lines
37 KiB
Python
1364 lines
37 KiB
Python
##################################################################
|
|
## (c) Copyright 2015- by Jaron T. Krogel ##
|
|
##################################################################
|
|
|
|
|
|
#====================================================================#
|
|
# generic.py #
|
|
# Base class for all Nexus classes (obj). Support for hidden #
|
|
# data UI (hidden). #
|
|
# #
|
|
# Content summary: #
|
|
# obj #
|
|
# Base class for all Nexus classes. #
|
|
# Inherits from AllAbilities and wraps all functions for UI. #
|
|
# Also basic working object/class for generic use. #
|
|
# Can function like a standard dict, also mixes in parts of #
|
|
# the list interface. #
|
|
# #
|
|
# generic #
|
|
# More efficient implementation of AllAbilities+obj interface. #
|
|
# Intended to allow for method namespace infringement without #
|
|
# loss of access to functionality. #
|
|
# Limited use so far. #
|
|
# #
|
|
# hidden #
|
|
# Like generic, but allows for hidden storage. #
|
|
# Can be used, e.g., to make an ordered object class. #
|
|
# See use in qmcpack_input.py. #
|
|
# #
|
|
#====================================================================#
|
|
|
|
|
|
import sys
|
|
import traceback
|
|
from copy import deepcopy
|
|
import pickle
|
|
from random import randint
|
|
|
|
from utilities import sorted_py2
|
|
|
|
|
|
class generic_settings:
|
|
devlog = sys.stdout
|
|
raise_error = False
|
|
#end class generic_settings
|
|
|
|
|
|
class NexusError(Exception):
|
|
None
|
|
#end class NexusError
|
|
|
|
|
|
exit_call = sys.exit
|
|
|
|
|
|
def nocopy(value):
|
|
return value
|
|
#end def nocopy
|
|
|
|
|
|
|
|
sorted_generic = sorted_py2
|
|
|
|
|
|
|
|
def log(*items,**kwargs):
|
|
indent = None
|
|
logfile = generic_settings.devlog
|
|
if len(kwargs)>0:
|
|
indent = kwargs.pop('indent' ,None )
|
|
logfile = kwargs.pop('logfile',logfile)
|
|
n = kwargs.pop('n',0)
|
|
if n!=0:
|
|
if indent is None:
|
|
indent = n*' '
|
|
else:
|
|
indent = n*indent
|
|
#end if
|
|
#end if
|
|
if len(kwargs)>0:
|
|
valid = 'indent logfile n'.split()
|
|
error('Invalid keyword arguments provided.\nInvalid keywords: {0}\nValid options are: {1}'.format(sorted(kwargs.keys()),valid),'log')
|
|
#end if
|
|
#end if
|
|
if len(items)==1 and isinstance(items[0],str):
|
|
s = items[0]
|
|
else:
|
|
s=''
|
|
for item in items:
|
|
s+=str(item)+' '
|
|
#end for
|
|
#end if
|
|
if len(s)>0:
|
|
if isinstance(indent,str):
|
|
s=indent+s.replace('\n','\n'+indent)
|
|
#end if
|
|
s += '\n'
|
|
#end if
|
|
logfile.write(s)
|
|
#end def log
|
|
|
|
|
|
def message(msg,header=None,post_header=' message:',indent=' ',logfile=None):
|
|
if logfile is None:
|
|
logfile = generic_settings.devlog
|
|
#end if
|
|
if header is None:
|
|
header = post_header.lstrip()
|
|
else:
|
|
header += post_header
|
|
#end if
|
|
log('\n '+header,logfile=logfile)
|
|
log(msg.rstrip(),indent=indent,logfile=logfile)
|
|
#end def message
|
|
|
|
|
|
def warn(msg,header=None,indent=' ',logfile=None):
|
|
if logfile is None:
|
|
logfile = generic_settings.devlog
|
|
#end if
|
|
post_header=' warning:'
|
|
message(msg,header,post_header,indent,logfile)
|
|
#end def warn
|
|
|
|
|
|
def error(msg,header=None,exit=True,trace=True,indent=' ',logfile=None):
|
|
if generic_settings.raise_error:
|
|
raise NexusError(msg)
|
|
#end if
|
|
if logfile is None:
|
|
logfile = generic_settings.devlog
|
|
#end if
|
|
post_header=' error:'
|
|
message(msg,header,post_header,indent,logfile)
|
|
if exit:
|
|
log(' exiting.\n')
|
|
if trace:
|
|
traceback.print_stack()
|
|
#end if
|
|
exit_call()
|
|
#end if
|
|
#end def error
|
|
|
|
|
|
|
|
class object_interface(object):
|
|
_logfile = sys.stdout
|
|
|
|
def __len__(self):
|
|
return len(self.__dict__)
|
|
#end def __len__
|
|
|
|
def __contains__(self,name):
|
|
return name in self.__dict__
|
|
#end def
|
|
|
|
def __getitem__(self,name):
|
|
return self.__dict__[name]
|
|
#end def __getitem__
|
|
|
|
def __setitem__(self,name,value):
|
|
self.__dict__[name]=value
|
|
#end def __setitem__
|
|
|
|
def __delitem__(self,name):
|
|
del self.__dict__[name]
|
|
#end def __delitem__
|
|
|
|
def __iter__(self):
|
|
for item in self.__dict__:
|
|
yield self.__dict__[item]
|
|
#end for
|
|
#end def __iter__
|
|
|
|
def __repr__(self):
|
|
s=''
|
|
for k in sorted_generic(self._keys()):
|
|
if not isinstance(k,str) or k[0]!='_':
|
|
v=self.__dict__[k]
|
|
if hasattr(v,'__class__'):
|
|
s+=' {0:<20} {1:<20}\n'.format(str(k),v.__class__.__name__)
|
|
else:
|
|
s+=' {0:<20} {1:<20}\n'.format(str(k),type(v))
|
|
#end if
|
|
#end if
|
|
#end for
|
|
return s
|
|
#end def __repr__
|
|
|
|
def __str__(self,nindent=1):
|
|
pad = ' '
|
|
npad = nindent*pad
|
|
s=''
|
|
normal = []
|
|
qable = []
|
|
for k,v in self._items():
|
|
if not isinstance(k,str) or k[0]!='_':
|
|
if isinstance(v,object_interface):
|
|
qable.append(k)
|
|
else:
|
|
normal.append(k)
|
|
#end if
|
|
#end if
|
|
#end for
|
|
normal = sorted_generic(normal)
|
|
qable = sorted_generic(qable)
|
|
indent = npad+18*' '
|
|
for k in normal:
|
|
v = self[k]
|
|
vstr = str(v).replace('\n','\n'+indent)
|
|
s+=npad+'{0:<15} = '.format(str(k))+vstr+'\n'
|
|
#end for
|
|
for k in qable:
|
|
v = self[k]
|
|
s+=npad+str(k)+'\n'
|
|
s+=v.__str__(nindent+1)
|
|
if isinstance(k,str):
|
|
s+=npad+'end '+k+'\n'
|
|
#end if
|
|
#end for
|
|
return s
|
|
#end def __str__
|
|
|
|
def __eq__(self,other):
|
|
if not hasattr(other,'__dict__'):
|
|
return False
|
|
#end if
|
|
eq = True
|
|
for sname in self.__dict__:
|
|
if sname not in other.__dict__:
|
|
return False
|
|
#end if
|
|
svar = self.__dict__[sname]
|
|
ovar = other.__dict__[sname]
|
|
stype = type(svar)
|
|
otype = type(ovar)
|
|
if stype!=otype:
|
|
return False
|
|
#end if
|
|
eqval = svar==ovar
|
|
if isinstance(eqval,bool):
|
|
eq &= eqval
|
|
else:
|
|
try: # accommodate numpy arrays implicitly
|
|
eq &= eqval.all()
|
|
except:
|
|
return False
|
|
#end try
|
|
#end if
|
|
#end for
|
|
return eq
|
|
#end def __eq__
|
|
|
|
def tree(self,depth=None,all=False,types=False,nindent=1):
|
|
if depth==nindent-1:
|
|
return ''
|
|
#end if
|
|
pad = ' '
|
|
npad = nindent*pad
|
|
s=''
|
|
normal = []
|
|
qable = []
|
|
for k,v in self._items():
|
|
if not isinstance(k,str) or k[0]!='_':
|
|
if isinstance(v,object_interface):
|
|
qable.append(k)
|
|
else:
|
|
normal.append(k)
|
|
#end if
|
|
#end if
|
|
#end for
|
|
normal.sort()
|
|
qable.sort()
|
|
indent = npad+18*' '
|
|
if all:
|
|
for k in normal:
|
|
v = self[k]
|
|
if types:
|
|
s+=npad+'{0:<15} = '.format(k)
|
|
if hasattr(v,'__class__'):
|
|
s+='{0:<20}'.format(v.__class__.__name__)
|
|
else:
|
|
s+='{0:<20}'.format(type(v))
|
|
#end if
|
|
else:
|
|
s+=npad+str(k)
|
|
#end if
|
|
s+='\n'
|
|
#end for
|
|
#end if
|
|
if all and depth!=nindent:
|
|
for k in qable:
|
|
v = self[k]
|
|
s+=npad+str(k)+'\n'
|
|
s+=v.tree(depth,all,types,nindent+1)
|
|
if isinstance(k,str):
|
|
s+=npad+'end '+k+'\n'
|
|
#end if
|
|
#end for
|
|
else:
|
|
for k in qable:
|
|
v = self[k]
|
|
if types:
|
|
s+=npad+'{0:<15} = '.format(k)
|
|
if hasattr(v,'__class__'):
|
|
s+='{0:<20}'.format(v.__class__.__name__)
|
|
else:
|
|
s+='{0:<20}'.format(type(v))
|
|
#end if
|
|
else:
|
|
s+=npad+str(k)
|
|
#end if
|
|
s+='\n'
|
|
s+=v.tree(depth,all,types,nindent+1)
|
|
#end for
|
|
#end if
|
|
return s
|
|
#end def tree
|
|
|
|
def data_repr(self,nindent=1,ret_str_keys=False):
|
|
pad = ' '
|
|
npad = nindent*pad
|
|
normal = []
|
|
qable = []
|
|
str_keys = True
|
|
for k,v in self._items():
|
|
k_str = isinstance(k,str)
|
|
str_keys &= k_str
|
|
if not k_str or k[0]!='_':
|
|
if isinstance(v,object_interface):
|
|
qable.append(k)
|
|
else:
|
|
normal.append(k)
|
|
#end if
|
|
#end if
|
|
#end for
|
|
normal = sorted_generic(normal)
|
|
qable = sorted_generic(qable)
|
|
if str_keys:
|
|
nkmax = 0
|
|
for k in normal:
|
|
nkmax = max(nkmax,len(k))
|
|
#end for
|
|
for k in qable:
|
|
nkmax = max(nkmax,len(k))
|
|
#end for
|
|
k_fmt = '{0:<'+str(nkmax)+'} = '
|
|
k_delim = '='
|
|
k_func = str
|
|
else:
|
|
nkmax = 20
|
|
k_fmt = '{0:<20} : '
|
|
k_delim = ':'
|
|
k_func = repr
|
|
o_delim = ''
|
|
#end if
|
|
print(str_keys,list(self.keys()))
|
|
indent = npad+(nkmax+3)*' '
|
|
if nindent==1:
|
|
if str_keys:
|
|
s = 'd = obj(\n'
|
|
else:
|
|
s = 'd = obj({\n'
|
|
#end if
|
|
else:
|
|
s=''
|
|
#end if
|
|
for k in normal:
|
|
v = self[k]
|
|
vstr = (repr(v)+',').replace('\n','\n'+indent)
|
|
s+=npad+k_fmt.format(k_func(k))+vstr+'\n'
|
|
#end for
|
|
for k in qable:
|
|
v = self[k]
|
|
sv,contains_str_keys = v.data_repr(nindent+1,ret_str_keys=True)
|
|
if contains_str_keys:
|
|
o_open = ''
|
|
o_close = ''
|
|
else:
|
|
o_open = '{'
|
|
o_close = '}'
|
|
#end if
|
|
s+=npad+k_func(k)+' {} obj({}\n'.format(k_delim,o_open)
|
|
s+=sv
|
|
s+=npad+pad+'{}),\n'.format(o_close)
|
|
#end for
|
|
if nindent==1:
|
|
if str_keys:
|
|
s += pad + ')\n'
|
|
else:
|
|
s += pad + '})\n'
|
|
#end if
|
|
#end if
|
|
if not ret_str_keys:
|
|
return s
|
|
else:
|
|
return s,str_keys
|
|
#end if
|
|
#end def data_repr
|
|
|
|
|
|
# dict interface
|
|
def keys(self):
|
|
return self.__dict__.keys()
|
|
#end def keys
|
|
|
|
def values(self):
|
|
return self.__dict__.values()
|
|
#end def values
|
|
|
|
def items(self):
|
|
return self.__dict__.items()
|
|
#end def items
|
|
|
|
def copy(self):
|
|
return deepcopy(self)
|
|
#end def copy
|
|
|
|
def clear(self):
|
|
self.__dict__.clear()
|
|
#end def clear
|
|
|
|
|
|
# save/load
|
|
def save(self,fpath=None):
|
|
if fpath is None:
|
|
fpath='./'+self.__class__.__name__+'.p'
|
|
#end if
|
|
fobj = open(fpath,'wb')
|
|
binary = pickle.HIGHEST_PROTOCOL
|
|
pickle.dump(self,fobj,binary)
|
|
fobj.close()
|
|
del fobj
|
|
del binary
|
|
return
|
|
#end def save
|
|
|
|
def load(self,fpath=None):
|
|
if fpath is None:
|
|
fpath='./'+self.__class__.__name__+'.p'
|
|
#end if
|
|
fobj = open(fpath,'rb')
|
|
try:
|
|
tmp = pickle.load(fobj)
|
|
except:
|
|
try:
|
|
tmp = pickle.load(fobj,encoding='latin1')
|
|
except:
|
|
# fallback for files created with protocol 5
|
|
# in environments that only support up to protocol 4
|
|
try:
|
|
import pickle5
|
|
tmp = pickle5.load(fobj)
|
|
except ImportError:
|
|
have_pickle5 = False
|
|
error("Highest pickle protocol in current python version is {}, but {} is written using a higher protocol. Install pickle5, e.g. via pip, to enable protocol 5 in python <= 3.7.x".format(pickle.HIGHEST_PROTOCOL, fpath))
|
|
#end try
|
|
#end try
|
|
#end try
|
|
fobj.close()
|
|
d = self.__dict__
|
|
d.clear()
|
|
for k,v in tmp.__dict__.items():
|
|
d[k] = v
|
|
#end for
|
|
del fobj
|
|
del tmp
|
|
return
|
|
#end def load
|
|
|
|
|
|
# log, warning, and error messages
|
|
def open_log(self,filepath):
|
|
self._logfile = open(filepath,'w')
|
|
#end def open_log
|
|
|
|
def close_log(self):
|
|
self._logfile.close()
|
|
#end def close_log
|
|
|
|
def write(self,s):
|
|
self._logfile.write(s)
|
|
#end def write
|
|
|
|
def log(self,*items,**kwargs):
|
|
if 'logfile' not in kwargs:
|
|
kwargs['logfile'] = self._logfile
|
|
#end if
|
|
log(*items,**kwargs)
|
|
#end def log
|
|
|
|
def warn(self,message,header=None):
|
|
if header is None:
|
|
header=self.__class__.__name__
|
|
#end if
|
|
warn(message,header,logfile=self._logfile)
|
|
#end def warn
|
|
|
|
def error(self,message,header=None,exit=True,trace=True):
|
|
if header==None:
|
|
header = self.__class__.__name__
|
|
#end if
|
|
error(message,header,exit,trace,logfile=self._logfile)
|
|
#end def error
|
|
|
|
@classmethod
|
|
def class_log(cls,message):
|
|
log(message,logfile=cls._logfile)
|
|
#end def class_log
|
|
|
|
@classmethod
|
|
def class_warn(cls,message,header=None,post_header=' Warning:'):
|
|
if header==None:
|
|
header=cls.__name__
|
|
#end if
|
|
warn(message,header,logfile=cls._logfile)
|
|
#end def class_warn
|
|
|
|
@classmethod
|
|
def class_error(cls,message,header=None,exit=True,trace=True,post_header=' Error:'):
|
|
if header==None:
|
|
header = cls.__name__
|
|
#end if
|
|
error(message,header,exit,trace,logfile=cls._logfile)
|
|
#end def class_error
|
|
|
|
@classmethod
|
|
def class_has(cls,k):
|
|
return hasattr(cls,k)
|
|
#end def classmethod
|
|
|
|
@classmethod
|
|
def class_keys(cls):
|
|
return cls.__dict__.keys()
|
|
#end def class_keys
|
|
|
|
@classmethod
|
|
def class_items(cls):
|
|
return cls.__dict__.items()
|
|
#end def class_items
|
|
|
|
@classmethod
|
|
def class_get(cls,k):
|
|
return getattr(cls,k)
|
|
#end def class_set
|
|
|
|
@classmethod
|
|
def class_set(cls,**kwargs):
|
|
for k,v in kwargs.items():
|
|
setattr(cls,k,v)
|
|
#end for
|
|
#end def class_set
|
|
|
|
@classmethod
|
|
def class_set_single(cls,k,v):
|
|
setattr(cls,k,v)
|
|
#end def class_set_single
|
|
|
|
@classmethod
|
|
def class_set_optional(cls,**kwargs):
|
|
for k,v in kwargs.items():
|
|
if not hasattr(cls,k):
|
|
setattr(cls,k,v)
|
|
#end if
|
|
#end for
|
|
#end def class_set_optional
|
|
|
|
|
|
# access preserving functions
|
|
# dict interface
|
|
def _keys(self,*args,**kwargs):
|
|
return object_interface.keys(self,*args,**kwargs)
|
|
def _values(self,*args,**kwargs):
|
|
object_interface.values(self,*args,**kwargs)
|
|
def _items(self,*args,**kwargs):
|
|
return object_interface.items(self,*args,**kwargs)
|
|
def _copy(self,*args,**kwargs):
|
|
return object_interface.copy(self,*args,**kwargs)
|
|
def _clear(self,*args,**kwargs):
|
|
object_interface.clear(self,*args,**kwargs)
|
|
# save/load
|
|
def _save(self,*args,**kwargs):
|
|
object_interface.save(self,*args,**kwargs)
|
|
def _load(self,*args,**kwargs):
|
|
object_interface.load(self,*args,**kwargs)
|
|
# log, warning, and error messages
|
|
def _open_log(self,*args,**kwargs):
|
|
object_interface.open_log(self,*args,**kwargs)
|
|
def _close_log(self,*args,**kwargs):
|
|
object_interface.close_log(self,*args,**kwargs)
|
|
def _write(self,*args,**kwargs):
|
|
object_interface.write(self,*args,**kwargs)
|
|
def _log(self,*args,**kwargs):
|
|
object_interface.log(self,*args,**kwargs)
|
|
def _error(self,*args,**kwargs):
|
|
object_interface.error(self,*args,**kwargs)
|
|
def _warn(self,*args,**kwargs):
|
|
object_interface.warn(self,*args,**kwargs)
|
|
|
|
#end class object_interface
|
|
|
|
|
|
|
|
class obj(object_interface):
|
|
|
|
def __init__(self,*vars,**kwargs):
|
|
for var in vars:
|
|
if isinstance(var,(dict,object_interface)):
|
|
for k,v in var.items():
|
|
self[k] = v
|
|
#end for
|
|
else:
|
|
self[var] = None
|
|
#end if
|
|
#end for
|
|
for k,v in kwargs.items():
|
|
self[k] = v
|
|
#end for
|
|
#end def __init__
|
|
|
|
|
|
# list interface
|
|
def append(self,value):
|
|
self[len(self)] = value
|
|
#end def append
|
|
|
|
|
|
# return representations
|
|
def list(self,*keys):
|
|
nkeys = len(keys)
|
|
if nkeys==0:
|
|
keys = self._sorted_keys()
|
|
elif nkeys==1 and isinstance(keys[0],(list,tuple)):
|
|
keys = keys[0]
|
|
#end if
|
|
values = []
|
|
for key in keys:
|
|
values.append(self[key])
|
|
#end if
|
|
return values
|
|
#end def list
|
|
|
|
def list_optional(self,*keys):
|
|
nkeys = len(keys)
|
|
if nkeys==0:
|
|
keys = self._sorted_keys()
|
|
elif nkeys==1 and isinstance(keys[0],(list,tuple)):
|
|
keys = keys[0]
|
|
#end if
|
|
values = []
|
|
for key in keys:
|
|
if key in self:
|
|
values.append(self[key])
|
|
else:
|
|
values.append(None)
|
|
#end if
|
|
#end if
|
|
return values
|
|
#end def list_optional
|
|
|
|
def tuple(self,*keys):
|
|
return tuple(obj.list(self,*keys))
|
|
#end def tuple
|
|
|
|
def dict(self,*keys):
|
|
nkeys = len(keys)
|
|
if nkeys==0:
|
|
keys = self._keys()
|
|
elif nkeys==1 and isinstance(keys[0],(list,tuple)):
|
|
keys = keys[0]
|
|
#end if
|
|
d = dict()
|
|
for k in keys:
|
|
d[k] = self[k]
|
|
#end for
|
|
return d
|
|
#end def dict
|
|
|
|
def to_dict(self):
|
|
d = dict()
|
|
for k,v in self._items():
|
|
if isinstance(v,obj):
|
|
d[k] = v._to_dict()
|
|
else:
|
|
d[k] = v
|
|
#end if
|
|
#end for
|
|
return d
|
|
#end def to_dict
|
|
|
|
def obj(self,*keys):
|
|
nkeys = len(keys)
|
|
if nkeys==0:
|
|
keys = self._keys()
|
|
elif nkeys==1 and isinstance(keys[0],(list,tuple)):
|
|
keys = keys[0]
|
|
#end if
|
|
o = obj()
|
|
for k in keys:
|
|
o[k] = self[k]
|
|
#end for
|
|
return o
|
|
#end def obj
|
|
|
|
def to_obj(self):
|
|
o = obj()
|
|
for k,v in self._items():
|
|
if isinstance(v,obj):
|
|
o[k] = v._to_obj()
|
|
else:
|
|
o[k] = v
|
|
#end if
|
|
#end for
|
|
return o
|
|
#end def to_obj
|
|
|
|
|
|
# list extensions
|
|
def first(self):
|
|
return self[min(self._keys())]
|
|
#end def first
|
|
|
|
def last(self):
|
|
return self[max(self._keys())]
|
|
#end def last
|
|
|
|
def select_random(self):
|
|
return self[randint(0,len(self)-1)]
|
|
#end def select_random
|
|
|
|
|
|
# dict extensions
|
|
def sorted_keys(self):
|
|
return sorted_generic(self._keys())
|
|
#end def sorted_keys
|
|
|
|
|
|
def random_key(self):
|
|
key = None
|
|
nkeys = len(self)
|
|
if nkeys>0:
|
|
key = list(self._keys())[randint(0,nkeys-1)]
|
|
#end if
|
|
return key
|
|
#end def random_key
|
|
|
|
|
|
def set(self,*objs,**kwargs):
|
|
for key,value in kwargs.items():
|
|
self[key]=value
|
|
#end for
|
|
if len(objs)>0:
|
|
for o in objs:
|
|
for k,v in o.items():
|
|
self[k] = v
|
|
#end for
|
|
#end for
|
|
#end if
|
|
return self
|
|
#end def set
|
|
|
|
def set_optional(self,*objs,**kwargs):
|
|
for key,value in kwargs.items():
|
|
if key not in self:
|
|
self[key]=value
|
|
#end if
|
|
#end for
|
|
if len(objs)>0:
|
|
for o in objs:
|
|
for k,v in o.items():
|
|
if k not in self:
|
|
self[k] = v
|
|
#end if
|
|
#end for
|
|
#end for
|
|
#end if
|
|
return self
|
|
#end def set_optional
|
|
|
|
def get(self,key,value=None): # follow dict interface, no plural
|
|
if key in self:
|
|
value = self[key]
|
|
#end if
|
|
return value
|
|
#end def get
|
|
|
|
def get_optional(self,key,value=None):
|
|
if key in self:
|
|
value = self[key]
|
|
#end if
|
|
return value
|
|
#end def get_optional
|
|
|
|
def get_required(self,key):
|
|
if key in self:
|
|
value = self[key]
|
|
else:
|
|
obj.error(self,'a required key is not present\nkey required: {0}\nkeys present: {1}'.format(key,self._sorted_keys()))
|
|
#end if
|
|
return value
|
|
#end def get_required
|
|
|
|
def delete(self,*keys):
|
|
nkeys = len(keys)
|
|
single = False
|
|
if nkeys==0:
|
|
keys = self._sorted_keys()
|
|
elif nkeys==1 and isinstance(keys[0],(list,tuple)):
|
|
keys = keys[0]
|
|
elif nkeys==1:
|
|
single = True
|
|
#end if
|
|
values = []
|
|
for key in keys:
|
|
values.append(self[key])
|
|
del self[key]
|
|
#end for
|
|
if single:
|
|
return values[0]
|
|
else:
|
|
return values
|
|
#end if
|
|
#end def delete
|
|
|
|
def delete_optional(self,key,value=None):
|
|
if key in self:
|
|
value = self[key]
|
|
del self[key]
|
|
#end if
|
|
return value
|
|
#end def delete_optional
|
|
|
|
def delete_required(self,key):
|
|
if key in self:
|
|
value = self[key]
|
|
del self[key]
|
|
else:
|
|
obj.error(self,'a required key is not present\nkey required: {0}\nkeys present: {1}'.format(key,self._sorted_keys()))
|
|
#end if
|
|
return value
|
|
#end def delete_required
|
|
|
|
def add(self,key,value):
|
|
self[key] = value
|
|
#end def add
|
|
|
|
def add_optional(self,key,value):
|
|
if key not in self:
|
|
self[key] = value
|
|
#end if
|
|
#end def add_optional
|
|
|
|
def transfer_from(self,other,keys=None,copy=False,overwrite=True):
|
|
if keys is None:
|
|
if isinstance(other,object_interface):
|
|
keys = other._keys()
|
|
else:
|
|
keys = other.keys()
|
|
#end if
|
|
#end if
|
|
if copy:
|
|
copier = deepcopy
|
|
else:
|
|
copier = nocopy
|
|
#end if
|
|
if overwrite:
|
|
for k in keys:
|
|
self[k]=copier(other[k])
|
|
#end for
|
|
else:
|
|
for k in keys:
|
|
if k not in self:
|
|
self[k]=copier(other[k])
|
|
#end if
|
|
#end for
|
|
#end if
|
|
#end def transfer_from
|
|
|
|
def transfer_to(self,other,keys=None,copy=False,overwrite=True):
|
|
if keys is None:
|
|
keys = self._keys()
|
|
#end if
|
|
if copy:
|
|
copier = deepcopy
|
|
else:
|
|
copier = nocopy
|
|
#end if
|
|
if overwrite:
|
|
for k in keys:
|
|
other[k]=copier(self[k])
|
|
#end for
|
|
else:
|
|
for k in keys:
|
|
if k not in self:
|
|
other[k]=copier(self[k])
|
|
#end if
|
|
#end for
|
|
#end if
|
|
#end def transfer_to
|
|
|
|
def move_from(self,other,keys=None,optional=False):
|
|
if keys is None:
|
|
if isinstance(other,object_interface):
|
|
keys = list(other._keys())
|
|
else:
|
|
keys = list(other.keys())
|
|
#end if
|
|
#end if
|
|
if not optional:
|
|
for k in keys:
|
|
self[k]=other[k]
|
|
del other[k]
|
|
#end for
|
|
else:
|
|
for k in keys:
|
|
if k in other:
|
|
self[k]=other[k]
|
|
del other[k]
|
|
#end if
|
|
#end for
|
|
#end if
|
|
#end def move_from
|
|
|
|
def move_to(self,other,keys=None,optional=False):
|
|
if keys is None:
|
|
keys = list(self._keys())
|
|
#end if
|
|
if not optional:
|
|
for k in keys:
|
|
other[k]=self[k]
|
|
del self[k]
|
|
#end for
|
|
else:
|
|
for k in keys:
|
|
if k in self:
|
|
other[k]=self[k]
|
|
del self[k]
|
|
#end if
|
|
#end for
|
|
#end if
|
|
#end def move_to
|
|
|
|
def move_from_optional(self,other,keys=None):
|
|
self.move_from(other,keys,optional=True)
|
|
#end def move_from_optional
|
|
|
|
def move_to_optional(self,other,keys=None):
|
|
self.move_to(other,keys,optional=True)
|
|
#end def move_to_optional
|
|
|
|
def copy_from(self,other,keys=None,deep=True):
|
|
obj.transfer_from(self,other,keys,copy=deep)
|
|
#end def copy_from
|
|
|
|
def copy_to(self,other,keys=None,deep=True):
|
|
obj.transfer_to(self,other,keys,copy=deep)
|
|
#end def copy_to
|
|
|
|
def extract(self,keys=None,optional=False):
|
|
ext = obj()
|
|
ext.move_from(self,keys,optional=optional)
|
|
return ext
|
|
#end def extract
|
|
|
|
def extract_optional(self,keys=None):
|
|
return self.extract(keys,optional=True)
|
|
#end def extract_optional
|
|
|
|
def check_required(self,keys,exit=True):
|
|
if not isinstance(keys,set):
|
|
keys = set(keys)
|
|
#end if
|
|
missing = keys-set(self.keys())
|
|
if exit and len(missing)>0:
|
|
self._error('required keys are missing\nmissing keys: {0}'.format(sorted_generic(missing)))
|
|
#end if
|
|
return missing
|
|
#end def check_required
|
|
|
|
def check_types(self,types,optional=False,exit=True):
|
|
kfail = None
|
|
tfail = None
|
|
if not optional:
|
|
for k,t in types.items():
|
|
if not isinstance(self[k],t):
|
|
kfail = k
|
|
tfail = t
|
|
break
|
|
#end if
|
|
#end for
|
|
else:
|
|
for k,t in types.items():
|
|
if k in self and not isinstance(self[k],t):
|
|
kfail = k
|
|
tfail = t
|
|
break
|
|
#end if
|
|
#end for
|
|
#end if
|
|
if exit and kfail is not None:
|
|
self._error('incorrect type encountered for key value\ntype required: {0}\ntype encountered: {1}\ninvalid key: {2}'.format(tfail.__name__,self[kfail].__class__.__name__,kfail))
|
|
#end if
|
|
return kfail,tfail
|
|
#end def check_types
|
|
|
|
def check_types_optional(self,types,exit=True):
|
|
return self.check_types(types,exit=exit,optional=True)
|
|
#end def check_types_optional
|
|
|
|
def shallow_copy(self):
|
|
new = self.__class__()
|
|
for k,v in self._items():
|
|
new[k] = v
|
|
#end for
|
|
return new
|
|
#end def shallow_copy
|
|
|
|
def inverse(self):
|
|
new = self.__class__()
|
|
for k,v in self._items():
|
|
new[v] = k
|
|
#end for
|
|
return new
|
|
#end def inverse
|
|
|
|
def path_exists(self,path):
|
|
o = self
|
|
if isinstance(path,str):
|
|
path = path.split('/')
|
|
#end if
|
|
for p in path:
|
|
if not p in o:
|
|
return False
|
|
#end if
|
|
o = o[p]
|
|
#end for
|
|
return True
|
|
#end def path_exists
|
|
|
|
def set_path(self,path,value=None):
|
|
o = self
|
|
cls = self.__class__
|
|
if isinstance(path,str):
|
|
path = path.split('/')
|
|
#end if
|
|
for p in path[0:-1]:
|
|
if not p in o:
|
|
o[p] = cls()
|
|
#end if
|
|
o = o[p]
|
|
#end for
|
|
o[path[-1]] = value
|
|
#end def set_path
|
|
|
|
def get_path(self,path,value=None):
|
|
o = self
|
|
if isinstance(path,str):
|
|
path = path.split('/')
|
|
#end if
|
|
for p in path[0:-1]:
|
|
if not p in o:
|
|
return value
|
|
#end if
|
|
o = o[p]
|
|
#end for
|
|
lp = path[-1]
|
|
if lp not in o:
|
|
return value
|
|
else:
|
|
return o[lp]
|
|
#end if
|
|
#end def get_path
|
|
|
|
def serial(self,s=None,path=None):
|
|
first = s is None
|
|
if first:
|
|
s = obj()
|
|
path = ''
|
|
#end if
|
|
for k,v in self._items():
|
|
p = path+str(k)
|
|
if isinstance(v,obj):
|
|
if len(v)==0:
|
|
s[p]=v
|
|
else:
|
|
v._serial(s,p+'/')
|
|
#end if
|
|
else:
|
|
s[p]=v
|
|
#end if
|
|
#end for
|
|
if first:
|
|
return s
|
|
#end if
|
|
#end def serial
|
|
|
|
|
|
# access preserving functions
|
|
# list interface
|
|
def _append(self,*args,**kwargs):
|
|
obj.append(self,*args,**kwargs)
|
|
# return representations
|
|
def _list(self,*args,**kwargs):
|
|
return obj.list(self,*args,**kwargs)
|
|
def _list_optional(self,*args,**kwargs):
|
|
return obj.list_optional(self,*args,**kwargs)
|
|
def _tuple(self,*args,**kwargs):
|
|
return obj.tuple(self,*args,**kwargs)
|
|
def _dict(self,*args,**kwargs):
|
|
return obj.dict(self,*args,**kwargs)
|
|
def _to_dict(self,*args,**kwargs):
|
|
return obj.to_dict(self,*args,**kwargs)
|
|
def _obj(self,*args,**kwargs):
|
|
return obj.obj(self,*args,**kwargs)
|
|
def _to_obj(self,*args,**kwargs):
|
|
return obj.to_obj(self,*args,**kwargs)
|
|
# list extensions
|
|
def _first(self,*args,**kwargs):
|
|
return obj.first(self,*args,**kwargs)
|
|
def _last(self,*args,**kwargs):
|
|
return obj.last(self,*args,**kwargs)
|
|
def _select_random(self,*args,**kwargs):
|
|
return obj.select_random(self,*args,**kwargs)
|
|
# dict extensions
|
|
def _sorted_keys(self,*args,**kwargs):
|
|
return obj.sorted_keys(self,*args,**kwargs)
|
|
def _random_key(self,*args,**kwargs):
|
|
obj.random_key(self,*args,**kwargs)
|
|
def _set(self,*args,**kwargs):
|
|
obj.set(self,*args,**kwargs)
|
|
def _set_optional(self,*args,**kwargs):
|
|
obj.set_optional(self,*args,**kwargs)
|
|
def _get(self,*args,**kwargs):
|
|
obj.get(self,*args,**kwargs)
|
|
def _get_optional(self,*args,**kwargs):
|
|
obj.get_optional(self,*args,**kwargs)
|
|
def _get_required(self,*args,**kwargs):
|
|
obj.get_required(self,*args,**kwargs)
|
|
def _delete(self,*args,**kwargs):
|
|
obj.delete(self,*args,**kwargs)
|
|
def _delete_optional(self,*args,**kwargs):
|
|
obj.delete_optional(self,*args,**kwargs)
|
|
def _delete_required(self,*args,**kwargs):
|
|
obj.delete_required(self,*args,**kwargs)
|
|
def _add(self,*args,**kwargs):
|
|
obj.add(self,*args,**kwargs)
|
|
def _add_optional(self,*args,**kwargs):
|
|
obj.add_optional(self,*args,**kwargs)
|
|
def _transfer_from(self,*args,**kwargs):
|
|
obj.transfer_from(self,*args,**kwargs)
|
|
def _transfer_to(self,*args,**kwargs):
|
|
obj.transfer_to(self,*args,**kwargs)
|
|
def _move_from(self,*args,**kwargs):
|
|
obj.move_from(self,*args,**kwargs)
|
|
def _move_to(self,*args,**kwargs):
|
|
obj.move_to(self,*args,**kwargs)
|
|
def _move_from_optional(self,*args,**kwargs):
|
|
obj.move_from_optional(self,*args,**kwargs)
|
|
def _move_to_optional(self,*args,**kwargs):
|
|
obj.move_to_optional(self,*args,**kwargs)
|
|
def _copy_from(self,*args,**kwargs):
|
|
obj.copy_from(self,*args,**kwargs)
|
|
def _copy_to(self,*args,**kwargs):
|
|
obj.copy_to(self,*args,**kwargs)
|
|
def _extract(self,*args,**kwargs):
|
|
obj.extract(self,*args,**kwargs)
|
|
def _extract_optional(self,*args,**kwargs):
|
|
obj.extract_optional(self,*args,**kwargs)
|
|
def _check_required(self,*args,**kwargs):
|
|
obj.check_required(self,*args,**kwargs)
|
|
def _check_types(self,*args,**kwargs):
|
|
obj.check_types(self,*args,**kwargs)
|
|
def _check_types_optional(self,*args,**kwargs):
|
|
obj.check_types_optional(self,*args,**kwargs)
|
|
def _shallow_copy(self,*args,**kwargs):
|
|
obj.shallow_copy(self,*args,**kwargs)
|
|
def _inverse(self,*args,**kwargs):
|
|
return obj.inverse(self,*args,**kwargs)
|
|
def _path_exists(self,*args,**kwargs):
|
|
obj.path_exists(self,*args,**kwargs)
|
|
def _set_path(self,*args,**kwargs):
|
|
obj.set_path(self,*args,**kwargs)
|
|
def _get_path(self,*args,**kwargs):
|
|
obj.get_path(self,*args,**kwargs)
|
|
def _serial(self,*args,**kwargs):
|
|
return obj.serial(self,*args,**kwargs)
|
|
|
|
#end class obj
|
|
|
|
|
|
|
|
|
|
|
|
class hobj(obj):
|
|
def __init__(self,*args,**kwargs):
|
|
obj.__init__(self,*args,**kwargs)
|
|
#end def __init__
|
|
|
|
@property
|
|
def _dict(self):
|
|
return self.__dict__
|
|
#end def _dict
|
|
|
|
@property
|
|
def _alt(self):
|
|
return self.__dict__
|
|
#end def _alt
|
|
|
|
def __len__(self):
|
|
return len(self._dict)
|
|
#end def __len__
|
|
|
|
def __contains__(self,name):
|
|
return name in self._dict
|
|
#end def __contains__
|
|
|
|
def __getitem__(self,name):
|
|
return self._dict[name]
|
|
#end def __getitem__
|
|
|
|
def __setitem__(self,name,value):
|
|
self._dict[name] = value
|
|
#end def __setitem__
|
|
|
|
def __delitem__(self,name):
|
|
del self._dict[name]
|
|
#end def __delitem__
|
|
|
|
def __iter__(self):
|
|
d = self._dict
|
|
for item in d.__dict__:
|
|
yield d[item]
|
|
#end for
|
|
#end def __iter__
|
|
|
|
def keys(self):
|
|
return self._dict.keys()
|
|
#end def keys
|
|
|
|
def values(self):
|
|
return self._dict.values()
|
|
#end def keys
|
|
|
|
def items(self):
|
|
return self._dict.items()
|
|
#end def items
|
|
|
|
def clear(self):
|
|
self._dict.clear()
|
|
#end def clear
|
|
|
|
# access preserving functions
|
|
# dict interface
|
|
def _keys(self,*args,**kwargs):
|
|
return hobj.keys(self,*args,**kwargs)
|
|
def _values(self,*args,**kwargs):
|
|
hobj.values(self,*args,**kwargs)
|
|
def _items(self,*args,**kwargs):
|
|
return hobj.items(self,*args,**kwargs)
|
|
def _clear(self,*args,**kwargs):
|
|
hobj.clear(self,*args,**kwargs)
|
|
#end class hobj
|
|
|
|
|
|
|
|
class hidden(hobj):
|
|
def __init__(self,*vals,**kwargs):
|
|
d = object.__getattribute__(self,'__dict__')
|
|
d['_hidden_'] = hobj()
|
|
d['_public_'] = hobj()
|
|
hobj.__init__(self,*vals,**kwargs)
|
|
#end def __init__
|
|
|
|
@property
|
|
def _dict(self):
|
|
return self.__dict__['_public_']
|
|
#end def __get_dict
|
|
|
|
@property
|
|
def _alt(self):
|
|
return self.__dict__['_hidden_']
|
|
#end def __alt
|
|
|
|
def __getattribute__(self,name):
|
|
d = object.__getattribute__(self,'__dict__')
|
|
if '_public_' in d:
|
|
p = d['_public_']
|
|
if name in p:
|
|
return p[name]
|
|
else:
|
|
return object.__getattribute__(self,name)
|
|
#end if
|
|
else:
|
|
return object.__getattribute__(self,name)
|
|
#end if
|
|
#end def __getattribute__
|
|
|
|
def __setattr__(self,name,value):
|
|
self._dict[name] = value
|
|
#end def __setattr__
|
|
|
|
def __delattr__(self,name):
|
|
del self._dict[name]
|
|
#end def __delattr__
|
|
|
|
def hidden(self):
|
|
return self.__dict__['_hidden_']
|
|
#end def hidden
|
|
|
|
def public(self):
|
|
return self.__dict__['_public_']
|
|
#end def public
|
|
|
|
def _hidden(self):
|
|
return hidden.hidden(self)
|
|
#end def _hidden
|
|
|
|
def _public(self):
|
|
return hidden.public(self)
|
|
#end def _public
|
|
|
|
def open_log(self,filepath):
|
|
self._alt._open_log(filepath)
|
|
#end def open_log
|
|
|
|
def close_log(self):
|
|
self._alt._close_log()
|
|
#end def close_log
|
|
|
|
def write(self,s):
|
|
self._alt._write(s)
|
|
#end def write
|
|
|
|
def log(self,*items,**kwargs):
|
|
self._alt._log(*items,**kwargs)
|
|
#end def log
|
|
|
|
def __repr__(self):
|
|
s=''
|
|
for k in self._sorted_keys():
|
|
if not isinstance(k,str) or k[0]!='_':
|
|
v=self._dict[k]
|
|
if hasattr(v,'__class__'):
|
|
s+=' {0:<20} {1:<20}\n'.format(k,v.__class__.__name__)
|
|
else:
|
|
s+=' {0:<20} {1:<20}\n'.format(k,type(v))
|
|
#end if
|
|
#end if
|
|
#end for
|
|
return s
|
|
#end def __repr__
|
|
|
|
# log, warning, and error messages
|
|
def _open_log(self,*args,**kwargs):
|
|
hidden.open_log(self,*args,**kwargs)
|
|
def _close_log(self,*args,**kwargs):
|
|
hidden.close_log(self,*args,**kwargs)
|
|
def _write(self,*args,**kwargs):
|
|
hidden.write(self,*args,**kwargs)
|
|
def _log(self,*args,**kwargs):
|
|
hidden.log(self,*args,**kwargs)
|
|
|
|
#end class hidden
|