Sitelet https://github.com/sqlalchemy/sqlalchemy/pull/12472
Skip to content

fix: compatibility with typing_extensions 4.13 and type statement - #12472

Closed
Daraan wants to merge 3 commits into
sqlalchemy:mainfrom
Daraan:main
Closed

Daraan wants to merge 3 commits into
sqlalchemy:mainfrom
Daraan:main

Conversation

@Daraan

@Daraan Daraan commented Mar 26, 2025 •

Copy link
Copy Markdown
Contributor

typing_extensions 4.13 has a backport typing_extensions.TypeAliasType which differs from typing.TypeAliasType which is created though the type statement.

isinstance which only checks for the typing_extensions variant will return False which can lead to errors.

(future) TODOs:

  • add tests for typing.TypeAliasType

Fixes: #12473

@Daraan
Daraan marked this pull request as draft March 26, 2025 17:46
@zzzeek

zzzeek commented Mar 26, 2025

Copy link
Copy Markdown
Member

hi -

we have been working with this change and we haven't seen a failing test case, do you have one?

@zzzeek

zzzeek commented Mar 26, 2025

Copy link
Copy Markdown
Member

oh we have one

@Daraan

Daraan commented Mar 26, 2025

Copy link
Copy Markdown
Contributor Author

I came here from python/typing_extensions#560 which I am looking into

VSCode was to eager in creating the PR :D

@Giuzzilla

Giuzzilla commented Mar 26, 2025 •

Copy link
Copy Markdown

I opened an issue with an example: #12473 (comment)

@CaselIT

CaselIT commented Mar 26, 2025

Copy link
Copy Markdown
Member

thanks for the pr. we will likely take it over since there is also a test to change, also there may be further cases were we are doing some assumptions

@Daraan
Daraan marked this pull request as ready for review March 26, 2025 18:24
@CaselIT
CaselIT requested a review from sqla-tester March 26, 2025 18:27

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, this is sqla-tester setting up my work on behalf of CaselIT to try to get revision 8861a5a of this pull request into gerrit so we can run tests and reviews and stuff

@sqla-tester

Copy link
Copy Markdown
Collaborator

New Gerrit review created for change 8861a5a: https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5825

@Daraan
Daraan requested a review from sqla-tester March 26, 2025 19:26

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, this is sqla-tester and I see you've pinged me for review. However, user Daraan is not authorized to initiate CI jobs. Please wait for a project member to do this!

@CaselIT

CaselIT commented Mar 26, 2025

Copy link
Copy Markdown
Member

I've updated the change. I had to duplicate a bunch of tests sadly.
@zzzeek can you take a look? I've also added an utility to automate the "get type from both typing and typing_extension"

@Viicos

Viicos commented Mar 26, 2025 •

Copy link
Copy Markdown
Contributor

Heads up from Pydantic: there is an edge case that need to be taken into account in Python 3.10. For more context, see the definition of typing_inspection.typing_objects.is_typealiastype() (that we use internally).

A simplified implementation would look like:

def is_typealiastype(obj):
    return type(obj) is not types.GenericAlias and isinstance(obj, (typing.TypeAliasType, typing_extensions.TypeAliasType))

@CaselIT

CaselIT commented Mar 26, 2025

Copy link
Copy Markdown
Member

when would that happen? if you use [] on a TypeAliasType?

@CaselIT

CaselIT commented Mar 26, 2025

Copy link
Copy Markdown
Member

when would that happen? if you use [] on a TypeAliasType?

seems so. it wasn't taken into consideration at all the generic typealiastype case. should not be hard to handle, but I think for sqlalchemy we should consider the generic alias of tat a tat

@CaselIT

CaselIT commented Mar 26, 2025

Copy link
Copy Markdown
Member

when would that happen? if you use [] on a TypeAliasType?

seems so. it wasn't taken into consideration at all the generic typealiastype case. should not be hard to handle, but I think for sqlalchemy we should consider the generic alias of tat a tat

for how we use this check in sqlalchemy it seems it's already accounted for since the generic types are stripped. will update the fn in any case just to be safe

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Federico Caselli (CaselIT) wrote:

code review left on gerrit

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

  • test/orm/declarative/test_typed_mapping.py (line 1298): this part is only on 2.0

@sqla-tester

Copy link
Copy Markdown
Collaborator

Federico Caselli (CaselIT) wrote:

the backport to 2.0 has some different test

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5825

@sqla-tester

Copy link
Copy Markdown
Collaborator

Michael Bayer (zzzeek) wrote:

recheck

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5825

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Michael Bayer (zzzeek) wrote:

recheck

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

  • test/orm/declarative/test_typed_mapping.py (line 1298): Done

@sqla-tester

Copy link
Copy Markdown
Collaborator

Federico Caselli (CaselIT) wrote:

it seems that 3.7 needs special handling

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

@Daraan

Daraan commented Mar 27, 2025

Copy link
Copy Markdown
Contributor Author

Federico Caselli (CaselIT) wrote:

it seems that 3.7 needs special handling

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

I have a fix for at least one; can I commit it here or work with gerrit? If the later can you give me a quick rundown how to push/commit to it

@CaselIT

CaselIT commented Mar 27, 2025

Copy link
Copy Markdown
Member

no commits here will be ignored since the change in gerrit is quite a bit different.

It's likely easier if you post a diff here. Note that I was inclined to just skip that on 3.7. No one is using type alias types on it.

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Daraan (Daraan) wrote:

Patch for the 3.7 tests as the TAT attributes are not availiable on a subscripted TATA (_GenericAlias)

diff --git a/test/base/test_typing_utils.py b/test/base/test_typing_utils.py
index bc83c5f2c..a9976c03a 100644
--- a/test/base/test_typing_utils.py
+++ b/test/base/test_typing_utils.py
@@ -425,21 +425,40 @@ class TestTyping(fixtures.TestBase):
         # generics
         eq_(sa_typing.pep695_values(TA_generic), {typing.List[TV]})
         eq_(sa_typing.pep695_values(TAext_generic), {typing.List[TV]})
-        eq_(sa_typing.pep695_values(TA_generic_typed), {typing.List[TV]})
-        eq_(sa_typing.pep695_values(TAext_generic_typed), {typing.List[TV]})
         eq_(sa_typing.pep695_values(TA_generic_null), {None, typing.List[TV]})
         eq_(
             sa_typing.pep695_values(TAext_generic_null),
             {None, typing.List[TV]},
         )
-        eq_(
-            sa_typing.pep695_values(TA_generic_null_typed),
-            {None, typing.List[TV]},
-        )
-        eq_(
-            sa_typing.pep695_values(TAext_generic_null_typed),
-            {None, typing.List[TV]},
-        )
+        if py38:
+            eq_(sa_typing.pep695_values(TA_generic_typed), {typing.List[TV]})
+            eq_(sa_typing.pep695_values(TAext_generic_typed), {typing.List[TV]})
+            eq_(
+                sa_typing.pep695_values(TAext_generic_null_typed),
+                {None, typing.List[TV]},
+            )
+            eq_(
+                sa_typing.pep695_values(TA_generic_null_typed),
+                {None, typing.List[TV]},
+            )
+        else:
+            # for 3.7 the attributes are only available on the origin
+            eq_(sa_typing.pep695_values(
+                typing_extensions.get_origin(TA_generic_typed)),
+                {typing.List[TV]}
+            )
+            eq_(sa_typing.pep695_values(
+                typing_extensions.get_origin(TAext_generic_typed)),
+                {typing.List[TV]}
+            )
+            eq_(sa_typing.pep695_values(
+                typing_extensions.get_origin(TAext_generic_null_typed)),
+                {None, typing.List[TV]}
+            )
+            eq_(
+                sa_typing.pep695_values(typing_extensions.get_origin(TA_generic_null_typed)),
+                {None, typing.List[TV]},
+            )
 
     def test_is_fwd_ref(self):
         eq_(sa_typing.is_fwd_ref(int), False)
@@ -526,9 +545,20 @@ class TestTyping(fixtures.TestBase):
         for t in type_aliases() + new_types():
             if t in false_negatives:
                 exp = False
-            else:
+            elif py38:
                 exp = "null" in t.__name__
-            eq_(sa_typing.includes_none(t), exp, str(t))
+                eq_(sa_typing.includes_none(t), exp, str(t))
+            else:
+                # on 3.7 the attributes are only available on the origin
+                origin = typing_extensions.get_origin(t)
+                if origin is None:
+                    # normal TypeAliasType
+                    exp = "null" in t.__name__
+                    eq_(sa_typing.includes_none(t), exp, str(t))
+                else:
+                    # subscripted TypeAliasType
+                    exp = "null" in origin.__name__
+                    eq_(sa_typing.includes_none(origin), exp, str(t))
 
         for t in annotated_l():
             eq_(

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

  • test/base/test_typing_utils.py (line 428): fix for 3.7 tests:
    the attributes are not forwarded to a subscribed TypeAliasType -> _GenericAlias
diff --git a/test/base/test_typing_utils.py b/test/base/test_typing_utils.py
index bc83c5f2c..a9976c03a 100644
--- a/test/base/test_typing_utils.py
+++ b/test/base/test_typing_utils.py
@@ -425,21 +425,40 @@ class TestTyping(fixtures.TestBase):
         # generics
         eq_(sa_typing.pep695_values(TA_generic), {typing.List[TV]})
         eq_(sa_typing.pep695_values(TAext_generic), {typing.List[TV]})
-        eq_(sa_typing.pep695_values(TA_generic_typed), {typing.List[TV]})
-        eq_(sa_typing.pep695_values(TAext_generic_typed), {typing.List[TV]})
         eq_(sa_typing.pep695_values(TA_generic_null), {None, typing.List[TV]})
         eq_(
             sa_typing.pep695_values(TAext_generic_null),
             {None, typing.List[TV]},
         )
-        eq_(
-            sa_typing.pep695_values(TA_generic_null_typed),
-            {None, typing.List[TV]},
-        )
-        eq_(
-            sa_typing.pep695_values(TAext_generic_null_typed),
-            {None, typing.List[TV]},
-        )
+        if py38:
+            eq_(sa_typing.pep695_values(TA_generic_typed), {typing.List[TV]})
+            eq_(sa_typing.pep695_values(TAext_generic_typed), {typing.List[TV]})
+            eq_(
+                sa_typing.pep695_values(TAext_generic_null_typed),
+                {None, typing.List[TV]},
+            )
+            eq_(
+                sa_typing.pep695_values(TA_generic_null_typed),
+                {None, typing.List[TV]},
+            )
+        else:
+            # for 3.7 the attributes are only available on the origin
+            eq_(sa_typing.pep695_values(
+                typing_extensions.get_origin(TA_generic_typed)),
+                {typing.List[TV]}
+            )
+            eq_(sa_typing.pep695_values(
+                typing_extensions.get_origin(TAext_generic_typed)),
+                {typing.List[TV]}
+            )
+            eq_(sa_typing.pep695_values(
+                typing_extensions.get_origin(TAext_generic_null_typed)),
+                {None, typing.List[TV]}
+            )
+            eq_(
+                sa_typing.pep695_values(typing_extensions.get_origin(TA_generic_null_typed)),
+                {None, typing.List[TV]},
+            )
  • test/base/test_typing_utils.py (line 530): In 3.7 a subscripted typing_extensions.TypeAliasType is a rather simple typing._GenericAlias; it lacks a __name__ field causing the tests to fail.
get_origin(t).__name__

will work with 3.7:

patch:

diff --git a/test/base/test_typing_utils.py b/test/base/test_typing_utils.py
index bc83c5f2c..04b3aa6c1 100644
--- a/test/base/test_typing_utils.py
+++ b/test/base/test_typing_utils.py
@@ -526,9 +545,20 @@ class TestTyping(fixtures.TestBase):
         for t in type_aliases() + new_types():
             if t in false_negatives:
                 exp = False
-            else:
+            elif py38:
                 exp = "null" in t.__name__
-            eq_(sa_typing.includes_none(t), exp, str(t))
+                eq_(sa_typing.includes_none(t), exp, str(t))
+            else:
+                # on 3.7 the attributes are only available on the origin
+                origin = typing_extensions.get_origin(t)
+                if origin is None:
+                    # normal TypeAliasType
+                    exp = "null" in t.__name__
+                    eq_(sa_typing.includes_none(t), exp, str(t))
+                else:
+                    # subscripted TypeAliasType
+                    exp = "null" in origin.__name__
+                    eq_(sa_typing.includes_none(origin), exp, str(t))
 
         for t in annotated_l():
             eq_(

@Daraan

Daraan commented Mar 27, 2025

Copy link
Copy Markdown
Contributor Author

no commits here will be ignored since the change in gerrit is quite a bit different.

It's likely easier if you post a diff here. Note that I was inclined to just skip that on 3.7. No one is using type alias types on it.

Posted a diff on gerrit; sadly I cannot edit there :/, hmm maybe on the original 5825?.

I had a bit trouble with disambiguating "no, commits here will be ignored" and "no commits will be ignored"😄, but I think I got it correctly that they are ignored.

@CaselIT

CaselIT commented Mar 27, 2025

Copy link
Copy Markdown
Member

I'm inclined to just skip those types in 37, since the lib code also seems to require an update, since it errors with

AttributeError: value

in

sqlalchemy/util/typing.py", line 387, in recursive_value
    value = inner_type.__value__

@Daraan

Daraan commented Mar 27, 2025

Copy link
Copy Markdown
Contributor Author

I'm inclined to just skip those types in 37, since the lib code also seems to require an update, since it errors with

AttributeError: value

in

sqlalchemy/util/typing.py", line 387, in recursive_value
    value = inner_type.__value__

Yes, makes more sense, and should be easier, to update the utility function for the py3.7 case :)

@CaselIT

CaselIT commented Mar 27, 2025

Copy link
Copy Markdown
Member

I think it's fine if we just tell people that use TAT on 3.7 to update the python version :)

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Federico Caselli (CaselIT) wrote:

code review left on gerrit

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

  • test/base/test_typing_utils.py (line 333): I'm not sure why this test has run even with this requires in the laterts pipeline

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Michael Bayer (zzzeek) wrote:

code review left on gerrit

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

  • test/base/test_typing_utils.py (line 333): I didnt test it b.c. i didnt have a python 3.7 here. ill go onto the jenkins worker and investigate

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Michael Bayer (zzzeek) wrote:

code review left on gerrit

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

  • test/base/test_typing_utils.py (line 333): the git checkout on the worker failed in an entirely new and very ominous way. going to see if it was a one off

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Federico Caselli (CaselIT) wrote:

code review left on gerrit

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

  • test/base/test_typing_utils.py (line 333): > Took 7 sec on ryzen1

always it :(

@sqla-tester sqla-tester left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Michael Bayer (zzzeek) wrote:

code review left on gerrit

View this in Gerrit at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826

  • test/base/test_typing_utils.py (line 428): the combination of these patches are failing and I'm not able to apply them, also I can't cut and paste from gerrit very easily since it does not allow me to scroll. I am going to get the python38 decorators through first, if you want to create a complete patch for all fixes in a single file you can attach it to the PR or github issue

@sqla-tester

Copy link
Copy Markdown
Collaborator

Gerrit review https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5825 has been merged. Congratulations! :)

@sqla-tester

Copy link
Copy Markdown
Collaborator

Gerrit review https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5826 has been merged. Congratulations! :)

sqlalchemy-bot pushed a commit that referenced this pull request Mar 27, 2025
Fixed regression caused by ``typing_extension==4.13.0`` that introduced
a different implementation for ``TypeAliasType`` while SQLAlchemy assumed
that it would be equivalent to the ``typing`` version.

Added test regarding generic TypeAliasType

Fixes: #12473
Closes: #12472
Pull-request: #12472
Pull-request-sha: 8861a5a

Change-Id: I053019a222546a625ed6d588314ae9f5b34c2f8a
(cherry picked from commit 61970f9d2b7809116b5a9d339b45d910e276b428)
@Daraan

Daraan commented Mar 27, 2025

Copy link
Copy Markdown
Contributor Author

A big thanks @ everyone for taking this over so fast.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

typing-extensions 4.13.0 possibly breaks ORM declarative codepaths that are deprecated in 2.0

6 participants