pyecoregen icon indicating copy to clipboard operation
pyecoregen copied to clipboard

from x import y vs. import x

Open AnNeub opened this issue 3 years ago • 1 comments

Hi @aranega

I try to create static code from complex ecore models like capella. I always run into the problem of circular includes. But I think this could be avoided if other modules are loaded by using import x instead of from x import y. So if you have a module like this

module examlple
__init__.py
from .one import Foo
from .one import helper

one.py
from example import two 

class Foo(two.Bar):
    def __init__(self):
        super().__init__()
        print('Init Foo')

def helper():
    print('Help')

def main():
    foo = Foo()

if __name__ == '__main__':
    main()

two.py
from example import helper

class Bar:
    def __init__(self):
        print('Init Bar')
        helper()
    

As far as I understood, by using from x import y y is loaded into the local namespace. Therefore example above will not work. but changing two.py to

two.py
import example

class Bar:
    def __init__(self):
        print('Init Bar')
        example.helper()
    

And it can be resolved. So instead loading single classifiers from different ecore files importing the whole package can maybe solve this issue. Maybe I find some time to dive deeper and can prepare a patch and some example. Hope you have a rough idea of the problem.

Maybe you can give me a hint how I easily get the containing package from the classifier in the code gen template.

Best regards, Andreas

AnNeub avatar Mar 07 '22 21:03 AnNeub

Hi @AnNeub !

I see exactly what you mean for the imports. You're right, if you use the from x import y, y is loaded in the local namespace. However, I think that even if you just call import x, it will try to solve it as a module, so to load it and if x has a circular import toward your main module and use an element from it as a superclass, depending which module you call as "main" one, it will fail.

# A.py
import B

class AA(object):
   ...
# B.py
import A

class B(A.AA):
   ...
$ python A.py    # works
$ python B.py    # fails because of the circular import

Perhaps for submodule, the solution you propose can work juste fine :) I need to try on tricky metamodels to see if it fixes this issue. This is not an easy issue to solve, definitely.

For capella, helped with @cgava, we tried to pull a static version using pyecore and we reached a version with the various experiements @cgava made. You can find the efforts here https://github.com/cgava/pyEcoreCapella We had to write a dedicated generator (a specific modification of pyecoregen) for this kind of metamodel with a lot of circular references, and you need to use the develop version of pyecore.

In any case, I'll try to work on that and to find a sexy solution that could either generate code in a different fashion for every metamodel, or a way of detecting circular imports and trigger a specific code generation in those cases (it would be the best I guess).

aranega avatar Mar 08 '22 10:03 aranega