0

I'm creating a webapp which uses SQLAlchemy to access the database. I'm getting stuck with two models which are referencing to each other and ending up in an circular import which throws the following exception:

--- SNIPP --- (output modified to hide software name)
  File "/opt/promethium/service/opt/xxxx/lib/python/api/server/server.py", line 11, in <module>
    from api.server.controllers import *
  File "/opt/promethium/service/opt/xxxx/lib/python/api/server/controllers/__init__.py", line 3, in <module>
    from messagescontroller import MessagesController
  File "/opt/promethium/service/opt/xxxx/lib/python/api/server/controllers/messagescontroller.py", line 7, in <module>
    from api.server.models import MessageModel, EmailModel, KeyModel, MessagerecipientModel
  File "/opt/promethium/service/opt/xxxx/lib/python/api/server/models/__init__.py", line 6, in <module>
    from keymodel import KeyModel
  File "/opt/promethium/service/opt/xxxx/lib/python/api/server/models/keymodel.py", line 18, in <module>
    from api.server.models import ApplicationModel, EmailModel
ImportError: cannot import name EmailModel

These are the files and their code:

__init__.py

from applicationmodel import ApplicationModel
# some other imports here
from emailmodel import EmailModel
from keymodel import KeyModel
# some more imports here

keymodel.py

from sqlalchemy import Column, Integer, String, Date
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, backref, deferred
from sqlalchemy.ext.declarative import _declarative_constructor 
from sqlalchemy import event

from pyncacoreapi.server.models import ApplicationModel, EmailModel
from pyncacoreapi.server.libs.store import Base

class KeyModel(ApplicationModel, Base):
    __tablename__ = "keys"

    id = Column(Integer, primary_key=True)
    email_id = Column(Integer, ForeignKey("emails.id"))
    email = relationship("EmailModel", uselist=False, backref=backref("keys"))
    symmetrickey = deferred(Column(String,unique=True))
    certificate = deferred(Column(String,unique=True))
    privatekey = deferred(Column(String,unique=True))
    publickey = deferred(Column(String,unique=True))
    keymaterial = Column(String,unique=False)

emailmodel.py

from sqlalchemy import Column, Integer, String, Date
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.ext.declarative import _declarative_constructor 

from pyncacoreapi.server.models import ApplicationModel, KeyModel, DomainModel

from pyncacoreapi.server.libs.store import Base, Db

from sqlalchemy import event

class EmailModel(ApplicationModel, Base):
    __tablename__ = "emails"

    id = Column(Integer, primary_key=True)
    email = Column(String, unique=True)
    domain_id = Column(Integer, ForeignKey("domains.id"))
    domain = relationship("DomainModel",backref=backref("emails", order_by=id))
    account_id = Column(Integer, ForeignKey("accounts.id"))
    account = relationship("AccountModel",backref=backref("emails", order_by=id))

What do i have to do to get this import stuff correct? Whats the best practice or the "golden rule" for that? Thanks for any help!!!!

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Thomas Spycher
  • 956
  • 13
  • 32

1 Answers1

0

In this specific case, there is no need to import EmailModel at all. Alter keymodel.py to remove the import:

from pyncacoreapi.server.models import ApplicationModel

SQLAlchemy postpones resolving references given as strings until the last possible moment anyway, so it doesn't matter here that EmailModel is defined yet or not. You are referring to it in the email relationship via a string.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343