-
Notifications
You must be signed in to change notification settings - Fork 102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using uuid.UUID with PotgreSQL's UUID #94
Comments
Fixes dropbox#94
@ilevkivskyi any idea how to approach this? SQLAlchemy uses this pattern all over the place, where the type depends on the passed arguments (eg. |
SQLAlchemy allows setting UUID columns to either a string representation of a UUID (e.g '46260785-9b7e-4a59-824f-af994a510673') or to a Python uuid.UUID object. Fixes dropbox#94
i also suffer from this issue. is there a way to explicitly override the type that i tried using annotations like |
UPDATE: there is a better way it seems the following does the trick. at the module level: import uuid
from typing import cast, TYPE_CHECKING
import sqlalchemy
import sqlalchemy.dialects.postgresql
# https://github.com/dropbox/sqlalchemy-stubs/issues/94
_PostgreSQLUUID = sqlalchemy.dialects.postgresql.UUID(as_uuid=True)
if TYPE_CHECKING:
PostgreSQLUUID = cast(sqlalchemy.types.TypeEngine[uuid.UUID], _PostgreSQLUUID)
else:
PostgreSQLUUID = _PostgreSQLUUID use in orm model classes then looks like this: class Foo(Base):
id = sqlalchemy.Column(PostgreSQLUUID, default=uuid.uuid4, primary_key=True) |
@wbolster Looks like you answered your own question. I think you can also just use if TYPE_CHECKING:
PostgreSQLUUID = sqlalchemy.types.TypeEngine[uuid.UUID]
else:
PostgreSQLUUID = sqlalchemy.dialects.postgresql.UUID(as_uuid=True) |
hmm, not sure.
|
This seems wrong, can you give an example? |
Could someone explain this workaround? The runtime value is obvious, but even after reading the source for |
try the type engine "trick" basically tells the sqlalchemy mypy plugin that this is a column that deals with uuid.UUID objects. |
(By the way, thanks for sharing the workaround!) |
this is an update to my solution posted earlier. the good news is that things can be simplified. 🥳 the ‘if TYPE_CHECKING’ block and the workarounds using redefinitions can be avoided altogether by using a string literal for the type annotation (since the types are generic in stubs but not at runtime). here's a full example; the 🧙 trick here is the import uuid
from typing import cast
import sqlalchemy
import sqlalchemy.dialects.postgresql
import sqlalchemy.ext.declarative
PostgreSQLUUID = cast(
"sqlalchemy.types.TypeEngine[uuid.UUID]",
sqlalchemy.dialects.postgresql.UUID(as_uuid=True),
)
metadata = sqlalchemy.MetaData()
Base = sqlalchemy.ext.declarative.declarative_base(metadata=metadata)
class SomeClass(Base):
id = sqlalchemy.Column(PostgreSQLUUID, default=uuid.uuid4, primary_key=True)
... # other columns go here |
it can even be made more strict by using a from typing import NewType
FooId = NewType("FooId", uuid.UUID)
PostgreSQLFooId = cast("sqlalchemy.types.TypeEngine[FooId]", PostgreSQLUUID)
class Foo(Base):
id = sqlalchemy.Column(PostgreSQLFooId, default=uuid.uuid4, primary_key=True) usage example: obj = session.query(Foo).one()
reveal_type(obj.id) # FooID, not uuid.UUID this means it's possible to have different |
The most ergonomic way to do this (although not in libraries, strictly in your own project code) is just to monkey-patch classes to add runtime support for Class[] syntax. This is what django-stubs project is doing internally for QuerySet and Manager: https://github.com/typeddjango/django-stubs/blob/master/mypy_django_plugin/django/context.py#L60 |
I have a model using PostgreSQL's UUID:
SQLAlchemy lets me create instances as follows:
However, the stubs here seem to only accept the latter, not the former:
Could support for the former be added?
(I tested with sqlalchemy-stubs master)
The text was updated successfully, but these errors were encountered: