def test_alias_function_static(): @EMetaclass class A(object): from_ = EAttribute(eType=EString) a = A() assert getattr(a, 'from', -1) == -1 alias('from', A.from_, eclass=A) assert getattr(a, 'from') is None @EMetaclass class B(object): as_ = EAttribute(eType=EInt) b = B() assert getattr(b, 'as', -1) == -1 alias('as', B.as_) assert getattr(b, 'as') is 0 b.as_ = 4 assert b.as_ == 4 assert getattr(b, 'as') == 4
def load_energy_system(self, name): # create a resourceSet that hold the contents of the esdl.ecore model and the instances we use/create rset = ResourceSet() # Assign files with the .esdl extension to the XMLResource instead of default XMI rset.resource_factory['esdl'] = lambda uri: XMLResource(uri) # Read the lastest esdl.ecore from github esdl_model_resource = rset.get_resource( HttpURI( 'https://raw.githubusercontent.com/EnergyTransition/ESDL/master/esdl/model/esdl.ecore' )) esdl_model = esdl_model_resource.contents[0] # print('Namespace: {}'.format(esdl_model.nsURI)) rset.metamodel_registry[esdl_model.nsURI] = esdl_model # Create a dynamic model from the loaded esdl.ecore model, which we can use to build Energy Systems esdl = DynamicEPackage(esdl_model) # fix python buildin 'from' that is also used in ProfileElement as attribute # use 'start' instead of 'from' when using a ProfileElement alias('start', esdl.ProfileElement.findEStructuralFeature('from')) # have a nice __repr__ for some ESDL classes when printing ESDL objects (includes all Assets and EnergyAssets) esdl.Item.python_class.__repr__ = lambda x: '{}: ({})'.format( x.name, EnergySystemHandler.attr_to_dict(x)) esdl.Carrier.python_class.__repr__ = lambda x: '{}: ({})'.format( x.name, EnergySystemHandler.attr_to_dict(x)) esdl.Geometry.python_class.__repr__ = lambda x: '{}: ({})'.format( x.name, EnergySystemHandler.attr_to_dict(x)) esdl.QuantityAndUnitType.python_class.__repr__ = lambda x: '{}: ({})'.format( x.id, EnergySystemHandler.attr_to_dict(x)) esdl.QuantityAndUnitReference.python_class.__repr__ = lambda x: '{}: ({})'.format( 'QuantityAndUnitReference', EnergySystemHandler.attr_to_dict(x)) esdl.KPI.python_class.__repr__ = lambda x: '{}: ({})'.format( x.name, EnergySystemHandler.attr_to_dict(x)) esdl.ProfileElement.python_class.__repr__ = lambda x: 'ProfileElement ({})'.format( EnergySystemHandler.attr_to_dict(x)) # load the ESDL file resource = rset.get_resource(URI(name)) es = resource.contents[0] # At this point, the model instance is loaded! # get notifications of changes in the EnergySystem model #observer = PrintNotification(es) #observer2 = PrintNotification(es.instance[0].area) # also return the esdlm and rset reference, so we can create esdl classes and store them as strings return es, resource, esdl, rset
def __init__(self, name=None): # create a resourceSet that hold the contents of the esdl.ecore model and the instances we use/create self.rset = ResourceSet() # Assign files with the .esdl extension to the XMLResource instead of default XMI self.rset.resource_factory['esdl'] = lambda uri: XMLResource(uri) # Read the esdl.ecore from the tmp folder esdl_model_resource = self.rset.get_resource( URI('tmp/esdl/esdl.ecore')) esdl_model = esdl_model_resource.contents[0] # print('Namespace: {}'.format(esdl_model.nsURI)) self.rset.metamodel_registry[esdl_model.nsURI] = esdl_model # Create a dynamic model from the loaded esdl.ecore model, which we can use to build Energy Systems self.esdl = DynamicEPackage(esdl_model) # fix python buildin 'from' that is also used in ProfileElement as attribute # use 'start' instead of 'from' when using a ProfileElement alias('start', self.esdl.ProfileElement.findEStructuralFeature('from')) # have a nice __repr__ for some ESDL classes when printing ESDL objects (includes all Assets and EnergyAssets) self.esdl.Item.python_class.__repr__ = lambda x: '{}: ({})'.format( x.name, EnergySystemHandler.attr_to_dict(x)) self.esdl.Carrier.python_class.__repr__ = lambda x: '{}: ({})'.format( x.name, EnergySystemHandler.attr_to_dict(x)) self.esdl.Geometry.python_class.__repr__ = lambda x: '{}: ({})'.format( x.name, EnergySystemHandler.attr_to_dict(x)) self.esdl.QuantityAndUnitType.python_class.__repr__ = lambda x: '{}: ({})'.format( x.id, EnergySystemHandler.attr_to_dict(x)) self.esdl.QuantityAndUnitReference.python_class.__repr__ = lambda x: '{}: ({})'.format( 'QuantityAndUnitReference', EnergySystemHandler.attr_to_dict(x)) self.esdl.KPI.python_class.__repr__ = lambda x: '{}: ({})'.format( x.name, EnergySystemHandler.attr_to_dict(x)) self.esdl.ProfileElement.python_class.__repr__ = lambda x: 'ProfileElement ({})'.format( EnergySystemHandler.attr_to_dict(x)) if name: self.name = name self.load_energy_system(name)
def __init__(self, energy_system=None): if energy_system is not None: self.energy_system = energy_system self.resource = None self.rset = ResourceSet() self.esid_uri_dict = {} self._set_resource_factories() # fix python builtin 'from' that is also used in ProfileElement as attribute # use 'start' instead of 'from' when using a ProfileElement # and make sure that it is serialized back as 'from' instead of 'from_' esdl.ProfileElement.from_.name = 'from' setattr(esdl.ProfileElement, 'from', esdl.ProfileElement.from_) alias('start', esdl.ProfileElement.from_) # also for FromToIntItem esdl.FromToIntItem.from_.name = 'from' setattr(esdl.FromToIntItem, 'from', esdl.FromToIntItem.from_) alias('start', esdl.FromToIntItem.from_) # also for FromToDoubleItem esdl.FromToDoubleItem.from_.name = 'from' setattr(esdl.FromToDoubleItem, 'from', esdl.FromToDoubleItem.from_) alias('start', esdl.FromToDoubleItem.from_) # add support for cloning of EObjects and coppy.copy() setattr(EObject, '__copy__', support_functions.clone) setattr(EObject, 'clone', support_functions.clone) # add support for deepcopying EObjects and copy.deepcopy() setattr(EObject, '__deepcopy__', support_functions.deepcopy) setattr(EObject, 'deepcopy', support_functions.deepcopy) # have a nice __repr__ for some ESDL classes when printing ESDL objects (includes all Assets and EnergyAssets) esdl.EnergySystem.__repr__ = \ lambda x: '{}: ({})'.format(x.name, EnergySystemHandler.attr_to_dict(x))
def test_alias_function_dynamic(): A = EClass('A') A.eStructuralFeatures.append(EAttribute('from', EString)) a = A() assert getattr(a, 'from_', -1) == -1 alias('from_', A.findEStructuralFeature('from'), eclass=A) assert a.from_ is None B = EClass('B') B.eStructuralFeatures.append(EAttribute('as', EInt)) b = B() assert getattr(b, 'as_', -1) == -1 alias('as_', B.findEStructuralFeature('as')) assert b.as_ is 0 b.as_ = 4 assert b.as_ == 4 assert getattr(b, 'as') == 4
def __init__(self): self.rset = None self.resource = None self.energy_system = None self._new_resource_set() esdl.ProfileElement.from_.name = 'from' setattr(esdl.ProfileElement, 'from', esdl.ProfileElement.from_) alias('start', esdl.ProfileElement.from_) esdl.FromToIntPerc.from_.name = 'from' setattr(esdl.FromToIntPerc, 'from', esdl.FromToIntPerc.from_) alias('start', esdl.FromToIntPerc.from_) esdl.FromToDoublePerc.from_.name = 'from' setattr(esdl.FromToDoublePerc, 'from', esdl.FromToDoublePerc.from_) alias('start', esdl.FromToDoublePerc.from_)
def __init__(self, energy_system=None): if energy_system is not None: self.energy_system = energy_system self.resource = None self.rset = ResourceSet() self.esid_uri_dict = {} self._set_resource_factories() # fix python builtin 'from' that is also used in ProfileElement as attribute # use 'start' instead of 'from' when using a ProfileElement # alias('start', esdl.ProfileElement.findEStructuralFeature('from')) esdl.ProfileElement.from_.name = 'from' setattr(esdl.ProfileElement, 'from', esdl.ProfileElement.from_) alias('start', esdl.ProfileElement.from_) esdl.FromToIntItem.from_.name = 'from' setattr(esdl.FromToIntItem, 'from', esdl.FromToIntItem.from_) alias('start', esdl.FromToIntItem.from_) esdl.FromToDoubleItem.from_.name = 'from' setattr(esdl.FromToDoubleItem, 'from', esdl.FromToDoubleItem.from_) alias('start', esdl.FromToDoubleItem.from_) # add support for shallow copying or cloning an object # it copies the object's attributes (e.g. clone an object), does only shallow copying def clone(self): """ Shallow copying or cloning an object It only copies the object's attributes (e.g. clone an object) Usage object.clone() or copy.copy(object) (as _copy__() is also implemented) :param self: :return: A clone of the object """ newone = type(self)() eclass = self.eClass for x in eclass.eAllStructuralFeatures(): if isinstance(x, EAttribute): #logger.trace("clone: processing attribute {}".format(x.name)) if x.many: eOrderedSet = newone.eGet(x.name) for v in self.eGet(x.name): eOrderedSet.append(v) else: newone.eSet(x.name, self.eGet(x.name)) return newone setattr(EObject, '__copy__', clone) setattr(EObject, 'clone', clone) """ Deep copying an EObject. Does not work yet for copying references from other resources than this one. """ def deepcopy(self, memo=None): logger.debug("deepcopy: processing {}".format(self)) first_call = False if memo is None: memo = dict() first_call = True if self in memo: return memo[self] copy: EObject = self.clone() logger.debug("Shallow copy: {}".format(copy)) eclass: EClass = self.eClass for x in eclass.eAllStructuralFeatures(): if isinstance(x, EReference): #logger.debug("deepcopy: processing reference {}".format(x.name)) ref: EReference = x value: EStructuralFeature = self.eGet(ref) if value is None: continue if ref.containment: if ref.many and isinstance(value, EAbstractSet): #clone all containment elements eAbstractSet = copy.eGet(ref.name) for ref_value in value: duplicate = ref_value.__deepcopy__(memo) eAbstractSet.append(duplicate) else: copy.eSet(ref.name, value.__deepcopy__(memo)) #else: # # no containment relation, but a reference # # this can only be done after a full copy # pass # now copy should a full copy, but without cross references memo[self] = copy if first_call: logger.debug("copying references") for k, v in memo.items(): eclass: EClass = k.eClass for x in eclass.eAllStructuralFeatures(): if isinstance(x, EReference): #logger.debug("deepcopy: processing x-reference {}".format(x.name)) ref: EReference = x orig_value: EStructuralFeature = k.eGet(ref) if orig_value is None: continue if not ref.containment: opposite = ref.eOpposite if opposite and opposite.containment: # do not handle eOpposite relations, they are handled automatically in pyEcore continue if x.many: eAbstractSet = v.eGet(ref.name) for orig_ref_value in orig_value: try: copy_ref_value = memo[ orig_ref_value] except KeyError: logger.warning( f'Cannot find reference of type {orig_ref_value.eClass.Name} \ for reference {k.eClass.name}.{ref.name} in deepcopy memo, using original' ) copy_ref_value = orig_ref_value eAbstractSet.append(copy_ref_value) else: try: copy_value = memo[orig_value] except KeyError: logger.warning( f'Cannot find reference of type {orig_value.eClass.name} of \ reference {k.eClass.name}.{ref.name} in deepcopy memo, using original' ) copy_value = orig_value v.eSet(ref.name, copy_value) return copy setattr(EObject, '__deepcopy__', deepcopy) setattr(EObject, 'deepcopy', deepcopy) # show deleted object from memory # setattr(EObject, '__del__', lambda x: print('Deleted {}'.format(x.eClass.name))) # def update_id(n: Notification): # if isinstance(n.feature, EAttribute): # #print(n) # if n.feature.name == 'id': # resource = n.notifier.eResource # if resource is not None and (n.kind != Kind.UNSET and n.kind != Kind.REMOVE): # print('ADDING to UUID dict {}#{}, notification type {}'.format(n.notifier.eClass.name, n.feature.name, n.kind.name)) # resource.uuid_dict[n.new] = n.notifier # if n.old is not None and n.old is not '': # del resource.uuid_dict[n.old] # observer = EObserver() # observer.notifyChanged = update_id # # old_init = EObject.__init__ # def new_init(self, **kwargs): # observer.observe(self) # old_init(self, **kwargs) # # setattr(EObject, '__init__', new_init) # Methods to automatically update the uuid_dict. # Currently disabled, because it does not work in all circumstances # This only works when the object which id is to be added to the dict is already part # of the energysystem xml tree, otherwise there is no way of knowing to which uuid_dict it should be added. # E.g. # > asset = esdl.Asset(id='uuid) # > asset.port.append(esdl.InPort(id='uuid)) # this does not work because asset is not part of the energy system yet # > area.asset.append(asset) #works for asset, but not for port. In order to have port working too, this statement # should be executed bofore adding the port... # old_set = EObject.__setattr__ # def updated_set(self, feature, value): # old_set(self, feature, value) # #if feature == 'id': # #print('Feature :{}#{}, value={}, resource={}'.format(self.eClass.name, feature, value, '?')) # #if isinstance(feature, EReference): # if hasattr(value, 'id') and feature[0] != '_': # print('*****Update uuid_dict {}#{} for {}#id'.format(self.eClass.name, feature, value.eClass.name)) # self.eResource.uuid_dict[value.id] = value # setattr(EObject, '__setattr__', updated_set) # # # # old_append = EAbstractSet.append # def updated_append(self, value, update_opposite=True): # old_append(self, value, update_opposite) # #print('EAbstractSet :{}, value={}, resource={}, featureEr={}'.format(self, value, value.eResource, self.feature.eResource)) # if hasattr(value, 'id'): # if self.feature.eResource: # print('****Update uuid_dict AbstractSet-{}#id'.format(value.eClass.name)) # self.feature.eResource.uuid_dict[value.id] = value # elif value.eResource: # print('****Update uuid_dict AbstractSet-{}#id'.format(value.eClass.name)) # value.eResource.uuid_dict[value.id] = value # # setattr(EAbstractSet, 'append', updated_append) # def toJSON(self): # return json.dumps(self, default=lambda o: list(o), # sort_keys=True, indent=4) # setattr(EOrderedSet, 'toJSON', toJSON) # have a nice __repr__ for some ESDL classes when printing ESDL objects (includes all Assets and EnergyAssets) esdl.EnergySystem.__repr__ = \ lambda x: '{}: ({})'.format(x.name, EnergySystemHandler.attr_to_dict(x))