#π Circular import hell...
24 messages Β· Page 1 of 1 (latest)
@pastel tiger
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
my message disappeard...
Just break the circular import. One of the 2 files is importing the other. Re-arrange it
@remote python is there no way to fix it?
I just told you. Don't have both files import each other
@remote python yea, I get it. But that seems like avoiding the problem. I come from rust land where you can do that all the time... it seems silly that you can't do it here.
I have
class ItemBase(BaseModel):
# Core Fields
id: uuid.UUID
name: str
description: Optional[str] = None
item_types: list[ItemTypeEnum]
# Manufacturer and Supplier information
manufacturer: Optional[str] = None
item_model_number: Optional[str] = None
serial_number: Optional[str] = None
suppliers: Optional[list[SupplierBaseSimple]] = None
# Location information
in_plant_location: Optional[str] = None
image_url: Optional[str] = None
# Parts
parts: Optional[list[ItemBaseSimple]]
# Item Requests
item_requests: Optional[list["ItemRequestBase"]] = None
# Metadata
status: ItemStatusEnum
created_at: datetime
updated_at: datetime
AND
class ItemRequestBase(BaseModel):
# Core Fields
id: uuid.UUID
description: Optional[str] = None
image_url: Optional[str] = None
requestor: Optional[str] = None
# Associated Equipment
item_id: Optional[uuid.UUID] = None
item: Optional["ItemBase"] = None
# Requested Parts
parts: Optional[List[PartRequest]] = None
# Metadata
status: ItemRequestStatusEnum = ItemRequestStatusEnum.ACTIVE
created_at: datetime
updated_at: datetime
They are two Pydantic models that model SQL tables that have a many to many relationship. It seems idiomatic to be able to import the files into each other.
why are these in 2 separate files? Why not put them into one?
they model different things. These are just small parts of their files.
putting them in the same file to avoid the python problem seems silly
but they depend on each other apparently
they have a many to many relationship... but it doesn't mean they belong in the same file.
Relationship models aside, they depend on each other. So when you import both of them to each other, both needs to wait for each file/module to finish importing (i.e. circular import problem)
its like saying
# a.py
from b import c
print(c)
d = 10
# b.py
from a import d
print(d)
c = 5
Neither are going to get what they want because one as to wait for the other to finish importing
So to fix this is basically put one into the other
# a.py
c = 5
d = 10
got it. Yea, seems silly... but the other tricks I looked at don't seem to be working.
there's this: https://medium.com/@hamana.hadrien/so-you-got-a-circular-import-in-python-e9142fe10591
Youβre just done writing code and you launch your app to see how it works; Here it is, you see this dreaded circular import error:
Are you only importing those for type hints?
because if so you can use TYPE_CHECKING from the builtin typing module
im not a frequent pydantic user and this does seem janky, but i believe you can solve this while keeping both files separate by deferring the runtime import to just after your model declaration, combined with .model_rebuild() for pydantic to evaluate your postponed annotations: ```py
item.py
from pydantic import BaseModel
class Item(BaseModel):
...
item_requests: "list[ItemRequest]" = []
from .item_request import ItemRequest
Item.model_rebuild() py
item_request.py
from pydantic import BaseModel
from .item import Item
class ItemRequest(BaseModel):
item: Item | None = None```
oh huh, the model_rebuild call isn't even needed, just the deferred import...
pydantic also doesn't seem to mind omitting .model_rebuild() if i only use a type checking guard (i.e. what slamsandwich said) for one of the models, as long as both modules are imported before ItemRequest() is instantiated: ```py
pkg/item.py
from pydantic import BaseModel
from .item_request import ItemRequest
class Item(BaseModel):
item_requests: list[ItemRequest] = [] py
pkg/item_request.py
from typing import TYPE_CHECKING
from pydantic import BaseModel
if TYPE_CHECKING:
from .item import Item
class ItemRequest(BaseModel):
item: "Item | None" = None py
pkg/main.py
from .item import Item
from .item_request import ItemRequest
ItemRequest() # works unless item.py import is removed
``` this is what i'd conventionally do to break a circular import for type annotations anyway, but pydantic is also doing some magic behind the scenes to automatically figure out the schema for Item / ItemRequest while python is executing your modules sequentially (item_request.py -> item.py)
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.