Hi,
I am having trouble creating a Model with a non-automatic primary key using the PrimaryKey type annotation using Python 3.11.
E.g. for this model I want to make the 'file_identifier' column the primary key but the automatic 'id' column/logic is used instead:
fromsqlormimportModel, PrimaryKeyclassCachedRecord(Model):
table="record"file_identifier: PrimaryKey[str]
file_revision: strsha1: str
Tracking that logic back, the mapper primary_key property returns None.
I can trace that back to the process_mapped_attributes() method which fails on the 'if annotated type' check (https://github.com/hyperflask/sqlorm/blob/main/src/sqlorm/model.py#L45) because .__class__ equates as a string (both literally and as a type), rather than an annotated type.
Asking AI it's said this is due to a change in Python 3.11+:
You’re hitting Python 3.11’s postponed evaluation of annotations: many annotations are stored as strings, and typing.Annotated no longer appears as t._AnnotatedAlias.
Fix by resolving annotations with typing.get_type_hints(..., include_extras=True) and using typing.get_origin/get_args to detect Annotated and Optional.
I don't fully understand what that's saying but I was able to workaround this problem with a modified version of its suggested code [1].
I imagine that code isn't suitable to use as-is though or if there's a better way to solve the problem. I may very well have done something wrong in my usage.
Apart from this, I've found this library really easy to use, and really closely matches what I've wanted as a database layer, so thanks for realising this.
# extra importsimportsysfromtypingimportget_type_hints, get_origin, get_argsclassModelMetaclass(abc.ABCMeta):
# ...@staticmethoddefprocess_mapped_attributes(dct):
module_name=dct.get("__module__", None)
globalns=sys.modules[module_name].__dict__ifmodule_nameandmodule_nameinsys.moduleselse {}
raw_annotations=dct.get("__annotations__", {}) or {}
try:
annotations=get_type_hints(
type("Tmp", (), {"__annotations__": raw_annotations}),
globalns=globalns,
localns=None,
include_extras=True,
)
exceptException:
annotations=raw_annotationsmapped_attrs= {}
forname, annotationinannotations.items():
primary_key=Falsenullable=Noneifget_origin(annotation) ist.Annotated:
ann_args=get_args(annotation)
base=ann_args[0] ifann_argselseannotationmeta=ann_args[1:] iflen(ann_args) >1else ()
primary_key=PrimaryKeyColumninmetaannotation=base# ...
Hi,
I am having trouble creating a Model with a non-automatic primary key using the
PrimaryKeytype annotation using Python 3.11.E.g. for this model I want to make the 'file_identifier' column the primary key but the automatic 'id' column/logic is used instead:
Tracking that logic back, the mapper
primary_keyproperty returnsNone.I can trace that back to the
process_mapped_attributes()method which fails on the 'if annotated type' check (https://github.com/hyperflask/sqlorm/blob/main/src/sqlorm/model.py#L45) because.__class__equates as a string (both literally and as a type), rather than an annotated type.Asking AI it's said this is due to a change in Python 3.11+:
I don't fully understand what that's saying but I was able to workaround this problem with a modified version of its suggested code [1].
I imagine that code isn't suitable to use as-is though or if there's a better way to solve the problem. I may very well have done something wrong in my usage.
Apart from this, I've found this library really easy to use, and really closely matches what I've wanted as a database layer, so thanks for realising this.