Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

making a Many Structural Feature #107

Open
Z-Rajaei opened this issue Jul 17, 2021 · 1 comment
Open

making a Many Structural Feature #107

Z-Rajaei opened this issue Jul 17, 2021 · 1 comment

Comments

@Z-Rajaei
Copy link

Z-Rajaei commented Jul 17, 2021

Hello,
I want to iterate on the elements that have references with my first element in this way:
‍‍‍‍‍
for ref in model.eClass.eAllReferences(): if model.eGet(ref)!=None: for element in model.eGet(ref): <some operations>

But when ref is a single value, I can not iterate on it.
I have used if ref.many ==False to check if it is single or many value, but I don't know how to do in both cases that it is single or many!
I can not use a function because I have many variable to be passed!
Do you have any solution for it? Is it possible create a EOrderedSet if it is a single value after if ref.many ==False checking?

Thank you.

@aranega
Copy link
Member

aranega commented Jul 20, 2021

Hi @Z-Rajaei ,

Sorry for the late answer, I read your email but no strong internet connection nor my laptop.
I think I understand more or less well what you are trying to do, you want to access to any elements from single or many relationships using a loop, wether they are single or many? (to harmonize the access to all the elements). Is that it?

Indeed, playing with many is the key to do that. There is basically two solutions. One using many and the other monkey patching the code and relying on some internal properties of PyEcore.

Considering a small metamodel and model as this one:

from pyecore.ecore import *


@EMetaclass
class B(object):
    ...

@EMetaclass
class A(object):
    single = EReference(eType=B, upper=1)
    many = EReference(eType=B, upper=-1)

a = A()
a.single = B()
a.many.update([B(), B()])

The first solution would be:

for ref in a.eClass.eAllReferences():
    values = a.eGet(ref)
    if values is None:
        continue
    values = values if ref.many else [values]
    for x in values:
        print(x)

This solution iterates on each relationships from the metaclass, discard the one sending None (the single references with no value), then check if yes or not it should place the accessed element in a collection or not. With that, you can harmonize the reflective access to each references.

The second solution relies on monkey patching:

from pyecore.valuecontainer import EValue

EValue.__iter__ = lambda self: iter([self._value])

for ref in a.eClass.eAllReferences():
    for x in a.__dict__.get(ref.name, []):
        print(x)

In PyEcore, EValue are invisible objects that wraps single values. This object is responsible for keeping in sync the parent of the affected object (if required), dealing with opposite...etc. This modification simply add the ability to this wrapper to be iterated on. However, as this object also follows Python's descriptor protocol, if directly accessed, the value wrapped by the EValue will be accessed instead of the EValue instance. Consequently, it is necessary to directly handle the internal dictionnary of the object with __dict__ to access the Evalue (the wrapper) instead of the wrapped value.

That should do the trick :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants