@erictraut I just realized what weirded me initially and still seems inconsistent now.
Looking at the dataclass_tranform example using sqlalchemy (which is what I stumbled upon initially)
from typing import Optional
from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, mapped_column
class Base(MappedAsDataclass, DeclarativeBase, kw_only=True):
id: Mapped[int] = mapped_column(
init=False, primary_key=True
)
class User(Base):
email: Mapped[str]
favorite_band: Mapped[Optional[str]] = mapped_column(default=None)
# Pyright: Fields without default values cannot appear after fields with default values Pyright (reportGeneralTypeIssues)
# Works in runtime
password: Mapped[str]
The code above has a typing issue but instantiating the model on runtime works, even though it seems like it shouldn’t with what we understand now.
Using naive dataclasses, it does not work in runtime
@dataclass(kw_only=True)
class A:
x: Optional[int] = None
# Throws error on definition
# TypeError: non-default argument 'z' follows default argument
@dataclass()
class B(A):
y: int
s: Optional[int] = None
z: int
So I tried to reproduce it using dataclasses_transform
def field(default: Any = None, init: bool = True, repr: bool = True) -> Any:
pass
@typing_extensions.dataclass_transform(field_specifiers=(field,))
class ModelMeta(type):
pass
class ModelBase(metaclass=ModelMeta):
def __init_subclass__(cls, kw_only: bool = False) -> None:
pass
class Base(ModelBase, kw_only=True):
pass
class Vehicle(Base):
b: Optional[str] = field(default=None)
c: int
Vehicle(b="1", c=1)
For that I didn’t get an error on definition, but I have an unexpected error on instantiation
Vehicle() takes no arguments
I tried to look at sqlalchemy’s usage but the code seems to convoluted and irrelevant for me right now to get into. I was hoping you could share your opinion on this matter, as although my initial issue is not as relevant, this seems like an inconsistency (in the implementation?) that caused this.