sqlalchemy-stubs icon indicating copy to clipboard operation
sqlalchemy-stubs copied to clipboard

Improve PostgreSQL's UUID support

Open bochecha opened this issue 5 years ago • 11 comments

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 #94

bochecha avatar Jul 25 '19 09:07 bochecha

While this fixes your particular use case - it will break stuff for other people. Now all UUID fields on a model will be an union of str and UUID and client code will need to handle those cases.

I think the right solution here is to extend mypy plugin. Basically what needs to be done is to hook into get_function_hook and return proper type (Instance with type argument set to str or UUID ) based on as_uuid argument.

rafales avatar Jul 26 '19 10:07 rafales

I wonder if it would be possible to use an overloaded function with literal types to fix this? Maybe something like subprocess.Popen: https://github.com/python/typeshed/blob/master/stdlib/3/subprocess.pyi#L809

JukkaL avatar Jul 26 '19 11:07 JukkaL

Interesting, I actually tried something like this and remember it didn't work. Maybe I did something wrong.

On Fri, Jul 26, 2019 at 1:59 PM Jukka Lehtosalo [email protected] wrote:

I wonder if it would be possible to use an overloaded function with literal types to fix this? Maybe something like subprocess.Popen: https://github.com/python/typeshed/blob/master/stdlib/3/subprocess.pyi#L809

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/dropbox/sqlalchemy-stubs/pull/95?email_source=notifications&email_token=AAHASBEHQ2GWFRDBIQKRTZ3QBLRKZA5CNFSM4IGY2EBKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD24L6VQ#issuecomment-515424086, or mute the thread https://github.com/notifications/unsubscribe-auth/AAHASBB5ZCNZYVZALMINUYDQBLRKZANCNFSM4IGY2EBA .

rafales avatar Jul 26 '19 12:07 rafales

I think we should try what @JukkaL proposes, using a union in this context may cause many false positives.

ilevkivskyi avatar Aug 07 '19 17:08 ilevkivskyi

I wonder if it would be possible to use an overloaded function with literal types to fix this? Maybe something like subprocess.Popen: https://github.com/python/typeshed/blob/master/stdlib/3/subprocess.pyi#L809

It seems I took too long to reply and this line moved? Otherwise I don't see how line 809 of current master relates to this. :confused:

I guess this is what you had in mind? https://github.com/python/typeshed/blob/3ad3ed82c75b4fb82f71f5500b50f18a98f12f49/stdlib/3/subprocess.pyi#L809

I just tried the following:

diff --git a/sqlalchemy-stubs/dialects/postgresql/base.pyi b/sqlalchemy-stubs/dialects/postgresql/base.pyi
index d910e5c..2c6917f 100644
--- a/sqlalchemy-stubs/dialects/postgresql/base.pyi
+++ b/sqlalchemy-stubs/dialects/postgresql/base.pyi
@@ -1,8 +1,9 @@
 from ... import schema
 from ...engine import default, reflection
 from ...sql import compiler, expression, sqltypes, type_api
-from typing import Any, Optional, Set, Type, Text, Pattern, Dict
+from typing import Any, Optional, Set, Type, Text, Pattern, Dict, overload
 from datetime import timedelta
+import uuid
 
 from sqlalchemy.types import INTEGER as INTEGER, BIGINT as BIGINT, SMALLINT as SMALLINT, VARCHAR as VARCHAR, \
     CHAR as CHAR, TEXT as TEXT, FLOAT as FLOAT, NUMERIC as NUMERIC, \
@@ -66,12 +67,20 @@ class BIT(sqltypes.TypeEngine[str]):
     def __init__(self, length: Optional[int] = ..., varying: bool = ...) -> None: ...
 PGBit = BIT
 
+@overload
 class UUID(sqltypes.TypeEngine[str]):
     __visit_name__: str = ...
     as_uuid: bool = ...
     def __init__(self, as_uuid: bool = ...) -> None: ...
     def bind_processor(self, dialect: Any): ...
     def result_processor(self, dialect: Any, coltype: Any): ...
+@overload
+class UUID(sqltypes.TypeEngine[uuid.UUID]):
+    __visit_name__: str = ...
+    as_uuid: bool = ...
+    def __init__(self, as_uuid: bool = ...) -> None: ...
+    def bind_processor(self, dialect: Any): ...
+    def result_processor(self, dialect: Any, coltype: Any): ...
 PGUuid = UUID
 
 class TSVECTOR(sqltypes.TypeEngine[str]):

However that doesn't work (same error message as #94). It seems @overload only works for functions and methods, not classes.

bochecha avatar Aug 09 '19 12:08 bochecha

You need to overload the constructor, not the class itself.

ilevkivskyi avatar Aug 09 '19 16:08 ilevkivskyi

@ilevkivskyi I made #185 to overload the constructor as per your suggestion. It seems to be pretty quiet here, it almost seems abandoned. Is it time for a community fork or is this just a temporary thing?

tdamsma avatar Nov 12 '20 12:11 tdamsma

Any news? I have a column uuid = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid4) When I pass an uuid while instantiating the model I get a warning saying that the uuid is expecting Optional[str].

ccrvlh avatar Jun 24 '21 01:06 ccrvlh

I made a PR but it seems this repo is a bit neglected by its maintainers. Also, with SQLAlchemy 1.4+ typing is maintained by zzzeek himself in a new repo

On Thu, 24 Jun 2021, 03:01 lowercase00, @.***> wrote:

Any news? I have a column uuid = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid4) When I pass an uuid while instantiating the model I get a warning saying that the uuid is expecting Optional[str].

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/dropbox/sqlalchemy-stubs/pull/95#issuecomment-867254409, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB4BSU57D4SGQSDW22RYSSDTUJ7XDANCNFSM4IGY2EBA .

tdamsma avatar Jun 24 '21 05:06 tdamsma

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

CLAassistant avatar Apr 16 '22 21:04 CLAassistant

Hi, I'm @bochecha in this ticket, but due to $circumstances I had to create a new account under my real name instead of my nickname.

I'm still happy to see people interested in following on this ticket and getting a way to find its way in, but if typing is now maintained by @zzzeek upstream I'm not sure we even need this ticket anymore ?

Sorry about not giving any sign of life this whole time.

($circumstances being my being hospitalized for 2 years and having to give up on all my floss activities during that time :disappointed:)

mbridon avatar Apr 17 '22 08:04 mbridon