Is there a general rule of thumb to follow with creating custom types to use across different files?
I'm currently trying to use my custom types across different modules. I would much rather have a single source of truth for custom types that need to be re-used.
Use case
I'm integrating with multiple webservices from the same provider for our item management system.
The catch here is that some of the webservices use shared properties like a (store number, service area, action code etc.). I've made custom types to restrict entries of invalid property values. ie:
ActionCodes = typing.Union[
typing.Literal["Add", "Update", "Delete"]
]
Which would be used like this in a pydantic model
class ItemInfo(pydantic.BaseModel):
ActionCode: ActionCodes = "Update"
OrgUnitNum: int = 0
ItemNum: int
PluNum: int
PluDescription: str
ServiceAreaNum: ServiceAreaNumber
Edits
"I keep ending up in this senario where I want to use a type but that type is already imported to a previous file (causing a circular import)."
As I've seen asked yes I have to import modules into my types.py file. Specifically from my models/ directory.
An example would be in need types.py in entity_models.py but also need types.py in entity_models.py and other files like update_prices.py.
types.py
# models
import models.models as models
import models.entity_models as entity_models
# typing
import typing
# freshiq list definitions
FreshIQPriceList = typing.List[entity_models.FreshIQPrices]
FreshIQPluList = typing.List[entity_models.FreshIQScalePlus]
FreshIQItemList = typing.List[entity_models.FreshIQItem]
# freshiq dict definitions
FreshIQPluDict = typing.Dict[str, entity_models.FreshIQScalePlus]
update_prices.py
# config
from config.databases import SALES
from config import mail as mail_config
from config import freshiq
# classes
from classes.do_entity_search import DoEntitySearch
# utility functions
from utils.job_runner import job_runner
from utils import mail
from utils import types as T
# models
from models import entity_models
from models import models
# python modyules
from datetime import date, timedelta
import logging
entity_models.py
# config
from config import freshiq
from config import env
# types
from utils import types as T
# pydantic
from pydantic import BaseModel, validator
# python modules
from datetime import datetime
from typing import Dict, List, Optional, Union, Literal, Any
Working directory
- classes/
- do_entity_search.py (uses types)
- webservice.py (uses types)
- item_webservice.py (uses types)
- config/
- databases.py
- env.py
- webservice_config.py (uses types)
- models/
- entity_models.py (uses types)
- item_models.py (uses types)
- utils/
- types.py (custom types)
- update_prices.py (runnable script)
- import_items.py (runnable script)
Error Message
Traceback (most recent call last):
File "C:\Users\janrico\Documents\GitHub\FreshIQ\jobs\update_prices.py", line 7, in <module>
from classes.do_entity_search import DoEntitySearch
File "C:\Users\janrico\Documents\GitHub\FreshIQ\jobs\classes\do_entity_search.py", line 6, in <module>
from utils.functools import update_item, insert_item, create_itemcode_map
File "C:\Users\janrico\Documents\GitHub\FreshIQ\jobs\utils\functools.py", line 7, in <module>
from models import entity_models
File "C:\Users\janrico\Documents\GitHub\FreshIQ\jobs\models\entity_models.py", line 6, in <module>
from utils import types as T
File "C:\Users\janrico\Documents\GitHub\FreshIQ\jobs\utils\types.py", line 10, in <module>
FreshIQPriceList = typing.List[entity_models.FreshIQPrices]
AttributeError: partially initialized module 'models.entity_models' has no attribute 'FreshIQPrices' (most likely due to a circular import)
My Solution (although not preferred)
I ended up moving relevant types that used enity_models into the entity_models.py file. This seems to work as expected but it defeats the purpose of having a single source of truth for types.