I write fastapi sqlmodel sqlalchemy project. I got type error in PyCharm:
expected type 'Literal["*"] | QueryableAttribute', got 'list[Account] | None' instead
error was caused by this code:
from sqlalchemy.orm import selectinload
class CRUDCounterPartyCommon(
CRUDBase[CounterParty, CounterpartyCommonCreateUpdateSchema, CounterpartyCommonCreateUpdateSchema]
):
async def get_by_uuid(self, db: AsyncSession, *, _uuid: uuid.UUID) -> Optional[CounterParty]:
counterparty = select(CounterParty).where(CounterParty.id == _uuid).options(selectinload(CounterParty.accounts))
Warning was caused by selectinload. What should I do to solve this problem?
Update
mypy says:
error: Argument 1 to "selectinload" has incompatible type "list[Account] | None"; expected "Literal['*'] | QueryableAttribute[Any]" [arg-type]
Base CRUD class that is ok according to PyCharm linter when we are talking about selectinload:
class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
async def get_by_field_name(
self,
db: AsyncSession,
field_name: str,
field_value: str,
_select: ModelType,
selection_load_options: Optional[List[Tuple]] = None,
conditions: Optional[List[Tuple]] = None,
joins: Optional[List[Tuple]] = None,
) -> ModelType:
query = select(_select)
if joins:
for table, condition in joins:
query = query.join(table, condition)
if selection_load_options:
for options_tuple in selection_load_options:
options_obj = None
for option in options_tuple:
if options_obj is None:
options_obj = selectinload(option)
else:
options_obj = options_obj.options(selectinload(option))
if options_obj:
query = query.options(options_obj)
if conditions:
for key, value, comparison in conditions:
query = query.where(comparison(key, value))
query = query.where(field_name == field_value)
try:
query = query.group_by(self.model.id)
except Exception:
pass
There is more to this puzzle which you choose not to tell us about.
It seems perfectly reasonable to me that
accountswould be an optionallist[Account]type. Consider imposing a non-NULL constraint, so it must at least be the empty list.It's unclear where the
Literal["*"] | QueryableAttributetype came from, but an MRO that mentions CounterpartyCommonCreateUpdateSchema seems a likely candidate. At least for debugging, try removing it to see if that changes whatmypysays. Also, I can't imagine why you chose to list it twice. The second occurrence produces no useful effect.There's more than one way to accomplish the aim of this call:
Somewhere you define a
relationship(). We could tack on a, lazy="selectin"parameter there, for the same effect. Thenmypywould have less visibility into what's happening and less reason to complain.You might also choose to use .awaitable_attrs.