'How to fix this circular import error in Python
I have build a Python wrapper for a REST API that currently returns the raw JSON data. My next step is to convert the JSON data into Python objects. For this reason, I've made a Resource class with all the necessary methods to convert a dict into the relevant object.
How do I fix this circular import error?
I have thought of removing the periods
field from the Calendar class, but them I'm limiting the functionality of the API.
# test.py
from my_project.endpoints import Calendars
from my_project.resources import Calendar
calendars = Calendars(username, password).list()
calendars = [Calendar(**calendar) for calendar in calendars]
# ImportError: cannot import name 'Calendar' from partially initialized module 'my_project.model.resources.calendar' (most likely due to a circular import)
# my_project/client.py
from dataclasses import dataclass, fields
@dataclass
class Resource:
def __post_init__(self, *_):
for f in fields(self):
value = getattr(self, f.name)
if f.type is list and value is not None:
astype = f.metadata.get("type", str)
setattr(self, f.name, [self.__cast(v, astype) for v in value])
else:
setattr(self, f.name, self.__cast(value, f.type))
@classmethod
def __cast(cls, value, astype):
if value is None:
return None
if astype is datetime:
return datetime.fromisoformat(value)
elif astype is date:
return datetime.fromisoformat(value).date()
elif astype == cls.__name__:
key = cls._key()
return cls(**{key: value})
elif issubclass(astype, Resource) and isinstance(value, dict):
return astype(**value)
elif issubclass(astype, Resource) and isinstance(value, (str, int)):
return astype(**{astype._key(): value})
else:
return astype(value)
@classmethod
def _key(cls) -> tuple:
for f in fields(cls):
if f.metadata.get("key"):
return f.name
# my_project/resources.py
from my_project.model.resources.calendar import Calendar
from my_project.model.resources.period import Period
from my_project.model.resources.periodType import PeriodType
__all__ = ["Calendar", "Period", "PeriodType"]
# my_project/model/resources/calender.py
from my_project.model.resources.period import Period
@dataclass
class Calendar(Resource):
calenderSeq: str = field(default=None)
name: str = field(default=None)
description: str = field(default=None)
periods: list = field(default=None, metadata={"type": Period})
# my_project/model/resources/period.py
from my_project.model.resources.calendar import Calendar
from my_project.model.resources.periodType import PeriodType
@dataclass
class Period(Resource):
periodSeq: str = field(default=None)
name: str = field(default=None)
description: str = field(default=None)
periodType: PeriodType = field(default=None)
calendar: Calendar = field(default=None)
Edit
As per the comment of Davis (thanks for the suggestion), I tried combining all the files into a single resources.py. Despite the from __future__ import annotations
, still got the error NameError: name 'Period' is not defined
.
# my_project/resources.py
from __future__ import annotations
from dataclasses import InitVar, dataclass, field
from datetime import date, datetime
from sapcommissions import Resource
@dataclass
class Calendar(Resource):
calenderSeq: str = field(default=None)
name: str = field(default=None)
description: str = field(default=None)
periods: list = field(default=None, metadata={"type": Period}) # error here
@dataclass
class Period(Resource):
periodSeq: str = field(default=None)
name: str = field(default=None)
description: str = field(default=None)
periodType: PeriodType = field(default=None)
calendar: Calendar = field(default=None)
@dataclass
class PeriodType(Resource):
periodTypeSeq: str = field(default=None)
name: str = field(default=None)
description: str = field(default=None)
level: int = field(default=None)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|