Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular imports in python3

I have a package which contain several files. Each file contains a class and the classes are interdependant. How can I avoid circular dependencies without putting all the code in one file. Is there a better way to refactor the code or is there a way to resolve the circular imports

This is the directory structure

.
|-- Complainant.py
|-- Complaint.py
`-- __init__.py

Complaint.py:

from .Complainant import Complainant

class Complaint(BaseDocument):
    ALL_STATUS = ["waiting","resolved", "rejected"]
    text = TextField()
    timestamp = DateTimeField()
    status = TextField()
    complainant_id = TextField()
    department_ids = ListField(TextField())

    def get_complainant(self):
        db = DBManager.db()
        complainant = Complainant.load(db, self.complainant_id)
        return complainant

Complainant.py

from .Complaint import Complaint

class Complainant(BaseDocument):
    account_type = TextField()
    account_handle = TextField()
    complaint_ids = ListField(TextField())

    def get_complaints(self):
        db = DBManager.db()
        complaints = [Complaint.load(db, i) for i in self.complaint_ids]
        return complaints

init.py

from .Complaint import Complaint
from .Complainant import Complainant

__all__ = [
    Complaint,
    Complainant
]
like image 436
freeza Avatar asked Oct 04 '16 11:10

freeza


1 Answers

In a system with circular dependencies, to avoid circular imports, you will generally have to put the interdependent parts in the same module.

In your case, only a fraction of the classes Complaint and Complainant are interdependent. You could refactor the modules to put the non-interdependent parts into classes in BaseComplaint.py and BaseComplainant.py, and use a third module to define the child classes Complaint and Complainant.

Directory structure:

.
|-- BaseComplainant.py
|-- BaseComplaint.py
|-- ComplaintComplainant.py
`-- __init__.py

BaseComplaint.py:

class BaseComplaint(BaseDocument):
    ALL_STATUS = ["waiting","resolved", "rejected"]
    text = TextField()
    timestamp = DateTimeField()
    status = TextField()
    complainant_id = TextField()
    department_ids = ListField(TextField())

BaseComplainant.py

class BaseComplainant(BaseDocument):
    account_type = TextField()
    account_handle = TextField()
    complaint_ids = ListField(TextField())

ComplaintComplainant.py (maybe you can find a better name)

from .BaseComplaint import BaseComplaint
from .BaseComplainant import BaseComplainant

class Complaint(BaseComplaint):
    def get_complainant(self):
        db = DBManager.db()
        complainant = Complainant.load(db, self.complainant_id)
        return complainant

class Complainant(BaseComplainant):
    def get_complaints(self):
        db = DBManager.db()
        complaints = [Complaint.load(db, i) for i in self.complaint_ids]
        return complaints

init.py

from .ComplaintComplainant import Complaint, Complainant

__all__ = [
    Complaint,
    Complainant
]
like image 150
flornquake Avatar answered Sep 30 '22 19:09

flornquake