SQLAlchemy 2.0.32__py3-none-any.whl → 2.0.34__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: SQLAlchemy
3
- Version: 2.0.32
3
+ Version: 2.0.34
4
4
  Summary: Database Abstraction Library
5
5
  Home-page: https://www.sqlalchemy.org
6
6
  Author: Mike Bayer
@@ -26,61 +26,61 @@ Classifier: Topic :: Database :: Front-Ends
26
26
  Requires-Python: >=3.7
27
27
  Description-Content-Type: text/x-rst
28
28
  License-File: LICENSE
29
- Requires-Dist: typing-extensions>=4.6.0
30
- Requires-Dist: greenlet!=0.4.17; python_version < "3.13" and (platform_machine == "aarch64" or (platform_machine == "ppc64le" or (platform_machine == "x86_64" or (platform_machine == "amd64" or (platform_machine == "AMD64" or (platform_machine == "win32" or platform_machine == "WIN32"))))))
31
- Requires-Dist: importlib-metadata; python_version < "3.8"
29
+ Requires-Dist: typing-extensions >=4.6.0
30
+ Requires-Dist: greenlet !=0.4.17 ; python_version < "3.13" and (platform_machine == "aarch64" or (platform_machine == "ppc64le" or (platform_machine == "x86_64" or (platform_machine == "amd64" or (platform_machine == "AMD64" or (platform_machine == "win32" or platform_machine == "WIN32"))))))
31
+ Requires-Dist: importlib-metadata ; python_version < "3.8"
32
32
  Provides-Extra: aiomysql
33
- Requires-Dist: greenlet!=0.4.17; extra == "aiomysql"
34
- Requires-Dist: aiomysql>=0.2.0; extra == "aiomysql"
33
+ Requires-Dist: greenlet !=0.4.17 ; extra == 'aiomysql'
34
+ Requires-Dist: aiomysql >=0.2.0 ; extra == 'aiomysql'
35
35
  Provides-Extra: aioodbc
36
- Requires-Dist: greenlet!=0.4.17; extra == "aioodbc"
37
- Requires-Dist: aioodbc; extra == "aioodbc"
36
+ Requires-Dist: greenlet !=0.4.17 ; extra == 'aioodbc'
37
+ Requires-Dist: aioodbc ; extra == 'aioodbc'
38
38
  Provides-Extra: aiosqlite
39
- Requires-Dist: greenlet!=0.4.17; extra == "aiosqlite"
40
- Requires-Dist: aiosqlite; extra == "aiosqlite"
41
- Requires-Dist: typing-extensions!=3.10.0.1; extra == "aiosqlite"
39
+ Requires-Dist: greenlet !=0.4.17 ; extra == 'aiosqlite'
40
+ Requires-Dist: aiosqlite ; extra == 'aiosqlite'
41
+ Requires-Dist: typing-extensions !=3.10.0.1 ; extra == 'aiosqlite'
42
42
  Provides-Extra: asyncio
43
- Requires-Dist: greenlet!=0.4.17; extra == "asyncio"
43
+ Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncio'
44
44
  Provides-Extra: asyncmy
45
- Requires-Dist: greenlet!=0.4.17; extra == "asyncmy"
46
- Requires-Dist: asyncmy!=0.2.4,!=0.2.6,>=0.2.3; extra == "asyncmy"
45
+ Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncmy'
46
+ Requires-Dist: asyncmy !=0.2.4,!=0.2.6,>=0.2.3 ; extra == 'asyncmy'
47
47
  Provides-Extra: mariadb_connector
48
- Requires-Dist: mariadb!=1.1.2,!=1.1.5,>=1.0.1; extra == "mariadb-connector"
48
+ Requires-Dist: mariadb !=1.1.2,!=1.1.5,>=1.0.1 ; extra == 'mariadb_connector'
49
49
  Provides-Extra: mssql
50
- Requires-Dist: pyodbc; extra == "mssql"
50
+ Requires-Dist: pyodbc ; extra == 'mssql'
51
51
  Provides-Extra: mssql_pymssql
52
- Requires-Dist: pymssql; extra == "mssql-pymssql"
52
+ Requires-Dist: pymssql ; extra == 'mssql_pymssql'
53
53
  Provides-Extra: mssql_pyodbc
54
- Requires-Dist: pyodbc; extra == "mssql-pyodbc"
54
+ Requires-Dist: pyodbc ; extra == 'mssql_pyodbc'
55
55
  Provides-Extra: mypy
56
- Requires-Dist: mypy>=0.910; extra == "mypy"
56
+ Requires-Dist: mypy >=0.910 ; extra == 'mypy'
57
57
  Provides-Extra: mysql
58
- Requires-Dist: mysqlclient>=1.4.0; extra == "mysql"
58
+ Requires-Dist: mysqlclient >=1.4.0 ; extra == 'mysql'
59
59
  Provides-Extra: mysql_connector
60
- Requires-Dist: mysql-connector-python; extra == "mysql-connector"
60
+ Requires-Dist: mysql-connector-python ; extra == 'mysql_connector'
61
61
  Provides-Extra: oracle
62
- Requires-Dist: cx-oracle>=8; extra == "oracle"
62
+ Requires-Dist: cx-oracle >=8 ; extra == 'oracle'
63
63
  Provides-Extra: oracle_oracledb
64
- Requires-Dist: oracledb>=1.0.1; extra == "oracle-oracledb"
64
+ Requires-Dist: oracledb >=1.0.1 ; extra == 'oracle_oracledb'
65
65
  Provides-Extra: postgresql
66
- Requires-Dist: psycopg2>=2.7; extra == "postgresql"
66
+ Requires-Dist: psycopg2 >=2.7 ; extra == 'postgresql'
67
67
  Provides-Extra: postgresql_asyncpg
68
- Requires-Dist: greenlet!=0.4.17; extra == "postgresql-asyncpg"
69
- Requires-Dist: asyncpg; extra == "postgresql-asyncpg"
68
+ Requires-Dist: greenlet !=0.4.17 ; extra == 'postgresql_asyncpg'
69
+ Requires-Dist: asyncpg ; extra == 'postgresql_asyncpg'
70
70
  Provides-Extra: postgresql_pg8000
71
- Requires-Dist: pg8000>=1.29.1; extra == "postgresql-pg8000"
71
+ Requires-Dist: pg8000 >=1.29.1 ; extra == 'postgresql_pg8000'
72
72
  Provides-Extra: postgresql_psycopg
73
- Requires-Dist: psycopg>=3.0.7; extra == "postgresql-psycopg"
73
+ Requires-Dist: psycopg >=3.0.7 ; extra == 'postgresql_psycopg'
74
74
  Provides-Extra: postgresql_psycopg2binary
75
- Requires-Dist: psycopg2-binary; extra == "postgresql-psycopg2binary"
75
+ Requires-Dist: psycopg2-binary ; extra == 'postgresql_psycopg2binary'
76
76
  Provides-Extra: postgresql_psycopg2cffi
77
- Requires-Dist: psycopg2cffi; extra == "postgresql-psycopg2cffi"
77
+ Requires-Dist: psycopg2cffi ; extra == 'postgresql_psycopg2cffi'
78
78
  Provides-Extra: postgresql_psycopgbinary
79
- Requires-Dist: psycopg[binary]>=3.0.7; extra == "postgresql-psycopgbinary"
79
+ Requires-Dist: psycopg[binary] >=3.0.7 ; extra == 'postgresql_psycopgbinary'
80
80
  Provides-Extra: pymysql
81
- Requires-Dist: pymysql; extra == "pymysql"
81
+ Requires-Dist: pymysql ; extra == 'pymysql'
82
82
  Provides-Extra: sqlcipher
83
- Requires-Dist: sqlcipher3-binary; extra == "sqlcipher"
83
+ Requires-Dist: sqlcipher3-binary ; extra == 'sqlcipher'
84
84
 
85
85
  SQLAlchemy
86
86
  ==========
@@ -1,4 +1,4 @@
1
- sqlalchemy/__init__.py,sha256=i0mVxtnBs8TF20PbrQJe7ftldXr46Jp4MmWaCO0F8Pw,13033
1
+ sqlalchemy/__init__.py,sha256=kW5kNSOI0cHm2Ioc_-ahxqHWmCDAWb_iqZZJsMYrKMU,13033
2
2
  sqlalchemy/events.py,sha256=k-ZD38aSPD29LYhED7CBqttp5MDVVx_YSaWC2-cu9ec,525
3
3
  sqlalchemy/exc.py,sha256=M_8-O1hd8i6gbyx-TapV400p_Lxq2QqTGMXUAO-YgCc,23976
4
4
  sqlalchemy/inspection.py,sha256=MF-LE358wZDUEl1IH8-Uwt2HI65EsQpQW5o5udHkZwA,5063
@@ -25,13 +25,13 @@ sqlalchemy/dialects/mssql/aioodbc.py,sha256=UQd9ecSMIML713TDnLAviuBVJle7P7i1FtqG
25
25
  sqlalchemy/dialects/mssql/base.py,sha256=TQekFOsor8Rc-cnDPmbq_JLQekKrHPtUdBdNsCYFw7w,132447
26
26
  sqlalchemy/dialects/mssql/information_schema.py,sha256=HswjDc6y0mPXCf_x6VyylHlBdBa4PSY6Evxmmlch700,8084
27
27
  sqlalchemy/dialects/mssql/json.py,sha256=evUACW2O62TAPq8B7QIPagz7jfc664ql9ms68JqiYzg,4816
28
- sqlalchemy/dialects/mssql/provision.py,sha256=RTVbgYLFAHzEnpVQDJroU8ji_10MqBTiZfyP9_-QNT4,5362
29
- sqlalchemy/dialects/mssql/pymssql.py,sha256=eZRLz7HGt3SdoZUjFBmA9BS43N7AhIASw7VPBPEJuG0,4038
28
+ sqlalchemy/dialects/mssql/provision.py,sha256=ZAtt6Div9NLIngMs8kyloxfphw0KDNMsnRCAVd7-esE,5593
29
+ sqlalchemy/dialects/mssql/pymssql.py,sha256=LAv43q4vBCB85OsAwHQItaQUYTYIO0QJ-jvzaBrswmY,4097
30
30
  sqlalchemy/dialects/mssql/pyodbc.py,sha256=vwM-vBlmRwrqxOc73P0sFOrBSwn24wzc5IkEOpalbXQ,27056
31
31
  sqlalchemy/dialects/mysql/__init__.py,sha256=bxbi4hkysUK2OOVvr1F49akUj1cky27kKb07tgFzI9U,2153
32
32
  sqlalchemy/dialects/mysql/aiomysql.py,sha256=-oMZnCqNsSki8mlQRTWIwiQPT1OVdZIuANkb90q8LAs,9999
33
33
  sqlalchemy/dialects/mysql/asyncmy.py,sha256=YpuuOh8VknEeqHqUXQGfQ3jhfO3Xb-vZv78Jq5cscJ0,10067
34
- sqlalchemy/dialects/mysql/base.py,sha256=1iN5wVw52gDRi5go-q6YsX8vCPwW-Mkd3ej3rrX2ai8,120957
34
+ sqlalchemy/dialects/mysql/base.py,sha256=8shrZRSnVwDXtl6ybaO6cvul_RZ34zEWqvpYW5sNfOQ,120986
35
35
  sqlalchemy/dialects/mysql/cymysql.py,sha256=eXT1ry0w_qRxjiO24M980c-8PZ9qSsbhqBHntjEiKB0,2300
36
36
  sqlalchemy/dialects/mysql/dml.py,sha256=HXJMAvimJsqvhj3UZO4vW_6LkF5RqaKbHvklAjor7yU,7645
37
37
  sqlalchemy/dialects/mysql/enumerated.py,sha256=ipEPPQqoXfFwcywNdcLlZCEzHBtnitHRah1Gn6nItcg,8448
@@ -49,7 +49,7 @@ sqlalchemy/dialects/mysql/reserved_words.py,sha256=ucKX2p2c3UnMq2ayZuOHuf73eXhu7
49
49
  sqlalchemy/dialects/mysql/types.py,sha256=L5cTCsMT1pTedszNEM3jSxFNZEMcHQLprYCZ0vmfsnA,24343
50
50
  sqlalchemy/dialects/oracle/__init__.py,sha256=p4-2gw7TT0bX_MoJXTGD4i8WHctYsK9kCRbkpzykBrc,1493
51
51
  sqlalchemy/dialects/oracle/base.py,sha256=cav9QxSLT75-JXhhFSneYT_y3coF6TmFkBa5fqQMrRI,119615
52
- sqlalchemy/dialects/oracle/cx_oracle.py,sha256=QcbM3I6ixtEqTdTMjik8IASE43dAE9LUzs-2g_Q_J4w,55258
52
+ sqlalchemy/dialects/oracle/cx_oracle.py,sha256=q8Nyj15UZCE2TWOmxuWp5ZsxiCiGMzqfd_9UkmjIja0,55235
53
53
  sqlalchemy/dialects/oracle/dictionary.py,sha256=7WMrbPkqo8ZdGjaEZyQr-5f2pajSOF1OTGb8P97z8-g,19519
54
54
  sqlalchemy/dialects/oracle/oracledb.py,sha256=fZRKGqNIwW9LG4i8yDOXABrucbfzn_yC86Od-BJ3PcM,13619
55
55
  sqlalchemy/dialects/oracle/provision.py,sha256=O9ZpF4OG6Cx4mMzLRfZwhs8dZjrJETWR402n9c7726A,8304
@@ -57,7 +57,7 @@ sqlalchemy/dialects/oracle/types.py,sha256=QK3hJvWzKnnCe3oD3rItwEEIwcoBze8qGg7VF
57
57
  sqlalchemy/dialects/postgresql/__init__.py,sha256=wwnNAq4wDQzrlPRzDNB06ayuq3L2HNO99nzeEvq-YcU,3892
58
58
  sqlalchemy/dialects/postgresql/_psycopg_common.py,sha256=7TudtgsPiSB8O5kX8W8KxcNYR8t5h_UHb86b_ChL0P8,5696
59
59
  sqlalchemy/dialects/postgresql/array.py,sha256=bWcame7ntmI_Kx6gmBX0-chwADFdLHeCvaDQ4iX8id8,13734
60
- sqlalchemy/dialects/postgresql/asyncpg.py,sha256=nfujNbmAjkVPPt9jhh5ZJp8QziZQJ0fMG4JNnLTdsag,40206
60
+ sqlalchemy/dialects/postgresql/asyncpg.py,sha256=se1HXkikKQFcR2D-15jS6iKIaQs-M8Y8ke99ih0Y4NM,41132
61
61
  sqlalchemy/dialects/postgresql/base.py,sha256=ed49Ode09deJF3jXr8V5sSHTwVoFVq0dlvNdP3mJaBQ,178989
62
62
  sqlalchemy/dialects/postgresql/dml.py,sha256=Pc69Le6qzmUHHb1FT5zeUSD31dWm6SBgdCAGW89cs3s,11212
63
63
  sqlalchemy/dialects/postgresql/ext.py,sha256=1bZ--iNh2O9ym7l2gXZX48yP3yMO4dqb9RpYro2Mj2Q,16262
@@ -75,12 +75,12 @@ sqlalchemy/dialects/postgresql/ranges.py,sha256=6CgV7qkxEMJ9AQsiibo_XBLJYzGh-2Zx
75
75
  sqlalchemy/dialects/postgresql/types.py,sha256=Jfxqw9JaKNOq29JRWBublywgb3lLMyzx8YZI7CXpS2s,7300
76
76
  sqlalchemy/dialects/sqlite/__init__.py,sha256=lp9DIggNn349M-7IYhUA8et8--e8FRExWD2V_r1LJk4,1182
77
77
  sqlalchemy/dialects/sqlite/aiosqlite.py,sha256=g3qGV6jmiXabWyb3282g_Nmxtj1jThxGSe9C9yalb-U,12345
78
- sqlalchemy/dialects/sqlite/base.py,sha256=GmDZ7DRgXVXWjx5BKSZgGzKmYHokMtCINM0p8bDmbAc,97557
78
+ sqlalchemy/dialects/sqlite/base.py,sha256=i1LolkwQLI86l_YwEpiIfN5Lh469H1mairKdmTxa9k4,99832
79
79
  sqlalchemy/dialects/sqlite/dml.py,sha256=9GE55WvwoktKy2fHeT-Wbc9xPHgsbh5oBfd_fckMH5Q,8443
80
80
  sqlalchemy/dialects/sqlite/json.py,sha256=Eoplbb_4dYlfrtmQaI8Xddd2suAIHA-IdbDQYM-LIhs,2777
81
81
  sqlalchemy/dialects/sqlite/provision.py,sha256=UCpmwxf4IWlrpb2eLHGbPTpCFVbdI_KAh2mKtjiLYao,5632
82
82
  sqlalchemy/dialects/sqlite/pysqlcipher.py,sha256=OL2S_05DK9kllZj6DOz7QtEl7jI7syxjW6woS725ii4,5356
83
- sqlalchemy/dialects/sqlite/pysqlite.py,sha256=USPhTjA19ks7VfzjlMXN_BkUpZiPH8J5ZyR4B9DBhVY,28045
83
+ sqlalchemy/dialects/sqlite/pysqlite.py,sha256=aDp47n0J509kl2hDchoaBKXEQVZtkux54DwfKytUAe4,28068
84
84
  sqlalchemy/engine/__init__.py,sha256=Stb2oV6l8w65JvqEo6J4qtKoApcmOpXy3AAxQud4C1o,2818
85
85
  sqlalchemy/engine/_py_processors.py,sha256=j9i_lcYYQOYJMcsDerPxI0sVFBIlX5sqoYMdMJlgWPI,3744
86
86
  sqlalchemy/engine/_py_row.py,sha256=wSqoUFzLOJ1f89kgDb6sJm9LUrF5LMFpXPcK1vUsKcs,3787
@@ -94,7 +94,7 @@ sqlalchemy/engine/events.py,sha256=c0unNFFiHzTAvkUtXoJaxzMFMDwurBkHiiUhuN8qluc,3
94
94
  sqlalchemy/engine/interfaces.py,sha256=fcVHOmnMo7JZLHzgSKoK3QsdVHH7kJ_AmrDvwW9Ka3k,112936
95
95
  sqlalchemy/engine/mock.py,sha256=yvpxgFmRw5G4QsHeF-ZwQGHKES-HqQOucTxFtN1uzdk,4179
96
96
  sqlalchemy/engine/processors.py,sha256=XyfINKbo-2fjN-mW55YybvFyQMOil50_kVqsunahkNs,2379
97
- sqlalchemy/engine/reflection.py,sha256=FlT5kPpKm7Lah50GNt5XcnlJWojTL3LD_x0SoCF9kfY,75127
97
+ sqlalchemy/engine/reflection.py,sha256=gwGs8y7x6py5z-ZWx3hQqQrwpHepMCTJyQcFwWJjPlw,75364
98
98
  sqlalchemy/engine/result.py,sha256=j6BI4Wj2bziQNQG5OlG_Cm4KcNWY9AoYvTXVlJUU-D8,77603
99
99
  sqlalchemy/engine/row.py,sha256=9AAQo9zYDL88GcZ3bjcQTwMT-YIcuGTSMAyTfmBJ_yM,12032
100
100
  sqlalchemy/engine/strategies.py,sha256=DqFSWaXJPL-29Omot9O0aOcuGL8KmCGyOvnPGDkAJoE,442
@@ -142,11 +142,11 @@ sqlalchemy/orm/_typing.py,sha256=DVBfpHmDVK4x1zxaGJPY2GoTrAsyR6uexv20Lzf1afc,497
142
142
  sqlalchemy/orm/attributes.py,sha256=lorOHBJvJJYndOuafWJhHBbQ1pR6FAyimhqz-mErBRQ,92534
143
143
  sqlalchemy/orm/base.py,sha256=re6A8ooMxLyfCAeQfhBwwxeJQkiH7EtzzOZIVIiTPlw,27466
144
144
  sqlalchemy/orm/bulk_persistence.py,sha256=MfFALcRkE3eKwxkntVM1ZcUhOphUFwAr1Fc21qJoobo,71403
145
- sqlalchemy/orm/clsregistry.py,sha256=29LyYiuj0qbebOpgW6DbBPNB2ikTweFQar1byCst7I0,17958
145
+ sqlalchemy/orm/clsregistry.py,sha256=IjoDZwWpjG42ji59L4M1EZvjBEoXPZykzENDtKWxU8A,17974
146
146
  sqlalchemy/orm/collections.py,sha256=WEKuUCRgLhDhJEIBhZ21UrE0pBOyRm2zxD20GvbgA9g,52243
147
147
  sqlalchemy/orm/context.py,sha256=pFFc-1ZjaV3aQMAO27UIh0W6NyLc30n2IbuWNprMtS8,112445
148
148
  sqlalchemy/orm/decl_api.py,sha256=_WPKQ_vSE5k2TLtNmkaxxYmvbhZvkRMrrvCeDxdqDQE,63998
149
- sqlalchemy/orm/decl_base.py,sha256=oeL7xrty2J81FyDx03dNe02BtZ-R6iYpum-BoA1rhik,82822
149
+ sqlalchemy/orm/decl_base.py,sha256=FTHf3bCVlg52KR6JWVEwuG3XjOaGQ5KJMYFYXastGhw,82832
150
150
  sqlalchemy/orm/dependency.py,sha256=hgjksUWhgbmgHK5GdJdiDCBgDAIGQXIrY-Tj79tbL2k,47631
151
151
  sqlalchemy/orm/descriptor_props.py,sha256=dR_h4Gvdtpcdp4sj_ZOR4P5Nng2J2vhsvFHouRLlntc,37244
152
152
  sqlalchemy/orm/dynamic.py,sha256=rWAZ-nfAkREuNjt8e_FRdqYrvHDdbODn1CcfyP8Y18k,9816
@@ -172,7 +172,7 @@ sqlalchemy/orm/strategies.py,sha256=Sd6IKV_ya_CBKzebwazRrWWabvZ0PqariUB7KKUIUrc,
172
172
  sqlalchemy/orm/strategy_options.py,sha256=-n44NV8QX-3uWjhFMA_R_7vYy-d57gJY9snB9JeOj-w,85341
173
173
  sqlalchemy/orm/sync.py,sha256=g7iZfSge1HgxMk9SKRgUgtHEbpbZ1kP_CBqOIdTOXqc,5779
174
174
  sqlalchemy/orm/unitofwork.py,sha256=fiVaqcymbDDHRa1NjS90N9Z466nd5pkJOEi1dHO6QLY,27033
175
- sqlalchemy/orm/util.py,sha256=u7Wd8Wc2V0Qu5EBTrt2taB1Clhnr2a8aK6LC9eIeKZw,80734
175
+ sqlalchemy/orm/util.py,sha256=Q0JT2JydyGiNiYT8AVe9B6jOdBRVHSOVDIcWOsXXIUQ,80929
176
176
  sqlalchemy/orm/writeonly.py,sha256=SYu2sAaHZONk2pW4PmtE871LG-O0P_bjidvKzY1H_zI,22305
177
177
  sqlalchemy/pool/__init__.py,sha256=qiDdq4r4FFAoDrK6ncugF_i6usi_X1LeJt-CuBHey0s,1804
178
178
  sqlalchemy/pool/base.py,sha256=WF4az4ZKuzQGuKeSJeyexaYjmWZUvYdC6KIi8zTGodw,52236
@@ -194,7 +194,7 @@ sqlalchemy/sql/crud.py,sha256=HBX4QPtW_PYYJmIKfNr-wE8IdEr963N24WXzFBUZOo0,56514
194
194
  sqlalchemy/sql/ddl.py,sha256=CIqMilCKfuQnF0lrZsQdTxgrbXqcTauKr0Ojzj77PFQ,45602
195
195
  sqlalchemy/sql/default_comparator.py,sha256=utXWsZVGEjflhFfCT4ywa6RnhORc1Rryo87Hga71Rps,16707
196
196
  sqlalchemy/sql/dml.py,sha256=pn0Lm1ofC5qVZzwGWFW73lPCiNba8OsTeemurJgwRyg,65614
197
- sqlalchemy/sql/elements.py,sha256=Vmn_ux-fwpKBoMyQPMxIAj8QrLZVDD9iCh6odPlfzbA,176378
197
+ sqlalchemy/sql/elements.py,sha256=YfccXzQc9DlgF8q15kDf-zKBUY_vpIe0FGaVDBPoic4,176544
198
198
  sqlalchemy/sql/events.py,sha256=iC_Q1Htm1Aobt5tOYxWfHHqNpoytrULORmUKcusH_-E,18290
199
199
  sqlalchemy/sql/expression.py,sha256=VMX-dLpsZYnVRJpYNDozDUgaj7iQ0HuewUKVefD57PE,7586
200
200
  sqlalchemy/sql/functions.py,sha256=kMMYplvuIHFAPwxBI03SizwaLcYEHzysecWk-R1V-JM,63762
@@ -202,9 +202,9 @@ sqlalchemy/sql/lambdas.py,sha256=DP0Qz7Ypo8QhzMwygGHYgRhwJMx-rNezO1euouH3iYU,492
202
202
  sqlalchemy/sql/naming.py,sha256=ZHs1qSV3ou8TYmZ92uvU3sfdklUQlIz4uhe330n05SU,6858
203
203
  sqlalchemy/sql/operators.py,sha256=himArRqBzrljob3Zfhi_ZS-Jleg1u6YFp0g3d7Co6IM,76106
204
204
  sqlalchemy/sql/roles.py,sha256=pOsVn_OZD7mF2gJByHf24Rjopt0_Hu3dUCEOK5t4KS8,7662
205
- sqlalchemy/sql/schema.py,sha256=XjSlSvJf6Ym8Y5Jt2c_TTAQ7OnOrnk9GU-RiJh2-yW0,229588
206
- sqlalchemy/sql/selectable.py,sha256=iGTCMsfxmVjPcD3aGJTpHSpF-ckXEJyn29M6rD5UJww,234550
207
- sqlalchemy/sql/sqltypes.py,sha256=NJnsB-ZC-oyrVBQzhV_sbRHlqFShKAU2FEX65fBj8Vg,126941
205
+ sqlalchemy/sql/schema.py,sha256=iFleWHkxi-3mKGiK_N1TzUqxnNwOpypB4bWDuAVQe8c,229717
206
+ sqlalchemy/sql/selectable.py,sha256=7QpgbIVz9AanhodMICFwDvaY2RdsTRSTvsRzD9Cnsds,236460
207
+ sqlalchemy/sql/sqltypes.py,sha256=fajBVE_CCJykrQpOOnb8_HFOKCSoUF48AxljJymvGk4,127330
208
208
  sqlalchemy/sql/traversals.py,sha256=3ScTC1fh1-y8Y478h_2Azmd2xdQdWPWkDve4YgrwMf8,33664
209
209
  sqlalchemy/sql/type_api.py,sha256=q_FieFRALHiRkhy5Bj-cVgFHa7DXF1dP23FaRRYKeho,83717
210
210
  sqlalchemy/sql/util.py,sha256=qGHQF-tPCj-m1FBerzT7weCanGcXU7dK5m-W7NHio-4,48077
@@ -219,8 +219,8 @@ sqlalchemy/testing/entities.py,sha256=IphFegPKbff3Un47jY6bi7_MQXy6qkx_50jX2tHZJR
219
219
  sqlalchemy/testing/exclusions.py,sha256=T8B01hmm8WVs-EKcUOQRzabahPqblWJfOidi6bHJ6GA,12460
220
220
  sqlalchemy/testing/pickleable.py,sha256=U9mIqk-zaxq9Xfy7HErP7UrKgTov-A3QFnhZh-NiOjI,2833
221
221
  sqlalchemy/testing/profiling.py,sha256=PbuPhRFbauFilUONeY3tV_Y_5lBkD7iCa8VVyH2Sk9Y,10148
222
- sqlalchemy/testing/provision.py,sha256=zXsw2D2Xpmw_chmYLsE1GXQqKQ-so3V8xU_joTcKan0,14619
223
- sqlalchemy/testing/requirements.py,sha256=9hJRdF7ePsuor5WT1UPgEV2nlA7pjlr92pVPINmwO9g,52518
222
+ sqlalchemy/testing/provision.py,sha256=3qFor_sN1FFlS7odUGkKqLUxGmQZC9XM67I9vQ_zeXo,14626
223
+ sqlalchemy/testing/requirements.py,sha256=uD7ZYOMZ0LQ0Lf8EsKWmDdRSnfcrjnXa8eSgTiIibOk,52655
224
224
  sqlalchemy/testing/schema.py,sha256=lr4GkGrGwagaHMuSGzWdzkMaj3HnS7dgfLLWfxt__-U,6513
225
225
  sqlalchemy/testing/util.py,sha256=qldXKw8gRJ4I2x3uXsBssYMqwatmcMFMTOveRQCmfDU,14469
226
226
  sqlalchemy/testing/warnings.py,sha256=fJ-QJUY2zY2PPxZJKv9medW-BKKbCNbA4Ns_V3YwFXM,1546
@@ -260,9 +260,9 @@ sqlalchemy/util/preloaded.py,sha256=az7NmLJLsqs0mtM9uBkIu10-841RYDq8wOyqJ7xXvqE,
260
260
  sqlalchemy/util/queue.py,sha256=CaeSEaYZ57YwtmLdNdOIjT5PK_LCuwMFiO0mpp39ybM,10185
261
261
  sqlalchemy/util/tool_support.py,sha256=9braZyidaiNrZVsWtGmkSmus50-byhuYrlAqvhjcmnA,6135
262
262
  sqlalchemy/util/topological.py,sha256=N3M3Le7KzGHCmqPGg0ZBqixTDGwmFLhOZvBtc4rHL_g,3458
263
- sqlalchemy/util/typing.py,sha256=UctfgugSTnFJgZraikXJbB-5RoV7oyccZmbf2NeRfoA,16671
264
- SQLAlchemy-2.0.32.dist-info/LICENSE,sha256=PA9Zq4h9BB3mpOUv_j6e212VIt6Qn66abNettue-MpM,1100
265
- SQLAlchemy-2.0.32.dist-info/METADATA,sha256=hG6dXB5GSsBurmqvonmwwtBvJlerDWuK-3ERzPExHQU,9581
266
- SQLAlchemy-2.0.32.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
267
- SQLAlchemy-2.0.32.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11
268
- SQLAlchemy-2.0.32.dist-info/RECORD,,
263
+ sqlalchemy/util/typing.py,sha256=VUVyYOXmPPlAW9e8OuVQ55Ij4b6jc0GPDEjY-Rlpnwo,17961
264
+ SQLAlchemy-2.0.34.dist-info/LICENSE,sha256=PA9Zq4h9BB3mpOUv_j6e212VIt6Qn66abNettue-MpM,1100
265
+ SQLAlchemy-2.0.34.dist-info/METADATA,sha256=TdwTMOhRN3N7sdV1_zHpx9GCBE_dm2jeU9_9UMTGYM8,9632
266
+ SQLAlchemy-2.0.34.dist-info/WHEEL,sha256=uCRv0ZEik_232NlR4YDw4Pv3Ajt5bKvMH13NUU7hFuI,91
267
+ SQLAlchemy-2.0.34.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11
268
+ SQLAlchemy-2.0.34.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.44.0)
2
+ Generator: setuptools (74.1.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
sqlalchemy/__init__.py CHANGED
@@ -269,7 +269,7 @@ from .types import Uuid as Uuid
269
269
  from .types import VARBINARY as VARBINARY
270
270
  from .types import VARCHAR as VARCHAR
271
271
 
272
- __version__ = "2.0.32"
272
+ __version__ = "2.0.34"
273
273
 
274
274
 
275
275
  def __go(lcls: Any) -> None:
@@ -22,10 +22,17 @@ from ...testing.provision import generate_driver_url
22
22
  from ...testing.provision import get_temp_table_name
23
23
  from ...testing.provision import log
24
24
  from ...testing.provision import normalize_sequence
25
+ from ...testing.provision import post_configure_engine
25
26
  from ...testing.provision import run_reap_dbs
26
27
  from ...testing.provision import temp_table_keyword_args
27
28
 
28
29
 
30
+ @post_configure_engine.for_db("mssql")
31
+ def post_configure_engine(url, engine, follower_ident):
32
+ if engine.driver == "pyodbc":
33
+ engine.dialect.dbapi.pooling = False
34
+
35
+
29
36
  @generate_driver_url.for_db("mssql")
30
37
  def generate_driver_url(url, driver, query_str):
31
38
  backend = url.get_backend_name()
@@ -103,6 +103,7 @@ class MSDialect_pymssql(MSDialect):
103
103
  "message 20006", # Write to the server failed
104
104
  "message 20017", # Unexpected EOF from the server
105
105
  "message 20047", # DBPROCESS is dead or not enabled
106
+ "The server failed to resume the transaction",
106
107
  ):
107
108
  if msg in str(e):
108
109
  return True
@@ -1349,7 +1349,7 @@ class MySQLCompiler(compiler.SQLCompiler):
1349
1349
 
1350
1350
  clauses = []
1351
1351
 
1352
- requires_mysql8_alias = (
1352
+ requires_mysql8_alias = statement.select is None and (
1353
1353
  self.dialect._requires_alias_for_on_duplicate_key
1354
1354
  )
1355
1355
 
@@ -62,7 +62,7 @@ hostname portion of the URL, without specifying a port, database name or
62
62
 
63
63
  Users of Oracle Cloud should use this syntax and also configure the cloud
64
64
  wallet as shown in cx_Oracle documentation `Connecting to Autononmous Databases
65
- <https://cx-oracle.readthedocs.io/en/latest/user_guide/connection_handling.html#connecting-to-autononmous-databases>`_.
65
+ <https://cx-oracle.readthedocs.io/en/latest/user_guide/connection_handling.html#autonomousdb>`_.
66
66
 
67
67
  SID Connections
68
68
  ^^^^^^^^^^^^^^^
@@ -844,25 +844,45 @@ class AsyncAdapt_asyncpg_connection(AdaptedConnection):
844
844
  else:
845
845
  return AsyncAdapt_asyncpg_cursor(self)
846
846
 
847
+ async def _rollback_and_discard(self):
848
+ try:
849
+ await self._transaction.rollback()
850
+ finally:
851
+ # if asyncpg .rollback() was actually called, then whether or
852
+ # not it raised or succeeded, the transation is done, discard it
853
+ self._transaction = None
854
+ self._started = False
855
+
856
+ async def _commit_and_discard(self):
857
+ try:
858
+ await self._transaction.commit()
859
+ finally:
860
+ # if asyncpg .commit() was actually called, then whether or
861
+ # not it raised or succeeded, the transation is done, discard it
862
+ self._transaction = None
863
+ self._started = False
864
+
847
865
  def rollback(self):
848
866
  if self._started:
849
867
  try:
850
- self.await_(self._transaction.rollback())
851
- except Exception as error:
852
- self._handle_exception(error)
853
- finally:
868
+ self.await_(self._rollback_and_discard())
854
869
  self._transaction = None
855
870
  self._started = False
871
+ except Exception as error:
872
+ # don't dereference asyncpg transaction if we didn't
873
+ # actually try to call rollback() on it
874
+ self._handle_exception(error)
856
875
 
857
876
  def commit(self):
858
877
  if self._started:
859
878
  try:
860
- self.await_(self._transaction.commit())
861
- except Exception as error:
862
- self._handle_exception(error)
863
- finally:
879
+ self.await_(self._commit_and_discard())
864
880
  self._transaction = None
865
881
  self._started = False
882
+ except Exception as error:
883
+ # don't dereference asyncpg transaction if we didn't
884
+ # actually try to call commit() on it
885
+ self._handle_exception(error)
866
886
 
867
887
  def close(self):
868
888
  self.rollback()
@@ -879,6 +899,7 @@ class AsyncAdapt_asyncpg_connection(AdaptedConnection):
879
899
  self.await_(self._connection.close(timeout=2))
880
900
  except (
881
901
  asyncio.TimeoutError,
902
+ asyncio.CancelledError,
882
903
  OSError,
883
904
  self.dbapi.asyncpg.PostgresError,
884
905
  ):
@@ -2588,8 +2588,8 @@ class SQLiteDialect(default.DefaultDialect):
2588
2588
  return
2589
2589
  UNIQUE_PATTERN = r'(?:CONSTRAINT "?(.+?)"? +)?UNIQUE *\((.+?)\)'
2590
2590
  INLINE_UNIQUE_PATTERN = (
2591
- r'(?:(".+?")|(?:[\[`])?([a-z0-9_]+)(?:[\]`])?) '
2592
- r"+[a-z0-9_ ]+? +UNIQUE"
2591
+ r'(?:(".+?")|(?:[\[`])?([a-z0-9_]+)(?:[\]`])?)[\t ]'
2592
+ r"+[a-z0-9_ ]+?[\t ]+UNIQUE"
2593
2593
  )
2594
2594
 
2595
2595
  for match in re.finditer(UNIQUE_PATTERN, table_data, re.I):
@@ -2624,15 +2624,69 @@ class SQLiteDialect(default.DefaultDialect):
2624
2624
  connection, table_name, schema=schema, **kw
2625
2625
  )
2626
2626
 
2627
- CHECK_PATTERN = r"(?:CONSTRAINT (.+) +)?" r"CHECK *\( *(.+) *\),? *"
2627
+ # Notes:
2628
+ # * The pattern currently matches any character for the name of the
2629
+ # constraint, including newline characters (re.S flag) as long as
2630
+ # none of the SQLite's table constraints keywords are encountered
2631
+ # by a negative lookahead.
2632
+ # This prevents the pattern from matching subsequent constraints
2633
+ # as part of the name.
2634
+ # This is only done for those keywords if seperated by spaces, to
2635
+ # support constraint names that contains them e.g. "check_value".
2636
+ #
2637
+ # * Because check constraint definitions can also contain newline
2638
+ # or tab characters, the pattern matches any character untill either
2639
+ # the beginning of the next constraint statement using a
2640
+ # non-capturing and non-consuming group, allowing the next one
2641
+ # to match, or the end of the table definition
2642
+ # e.g. newline and closing ')'.
2643
+ CHECK_PATTERN = r"""
2644
+ # Non-capturing group for the name part of named check constraints.
2645
+ # This group is optional as unnamed check constraints can exist.
2646
+ (?:
2647
+ # Match beginning of constraint definition seperated by whitespace.
2648
+ CONSTRAINT\s
2649
+
2650
+ # First capturing group that matches the actual name of the constraint.
2651
+ # Any characters is allowed, as long as none of the reserved table
2652
+ # constraint keywords are encountered using a negative lookahead.
2653
+ ((?:(?!\sPRIMARY\s|\sFOREIGN\sKEY|\sUNIQUE\s|\sCHECK\s).)+)
2654
+
2655
+ # End of optional non-capturing name group seperated by whitespace.
2656
+ \s)?
2657
+
2658
+ # Match beginning of the check expression with starting parenthesis
2659
+ # and optional whitespace.
2660
+ CHECK\s?\(
2661
+
2662
+ # Match actual expression, which can be any character.
2663
+ (.+?)
2664
+
2665
+ # End parenthesis of the check expression.
2666
+ \)
2667
+
2668
+ # Non-capturing group that helps denote the end of the check
2669
+ # expression part.
2670
+ # This can either be (1) the beginning of the next constraint,
2671
+ # or (2) the end of the table definition.
2672
+ (?:
2673
+
2674
+ # (1) Matches end of check constraint with trailing comma,
2675
+ # optional whitespace (including newline), and the beginning
2676
+ # of the next constraint (either named or unnamed).
2677
+ ,[\s\n]*(?=CONSTRAINT|CHECK|UNIQUE|FOREIGN|PRIMARY)
2678
+ # OR operator, seperating (1) & (2)
2679
+ |
2680
+ # (2) Matches end parenthesis of table definition, seperated by
2681
+ # newline.
2682
+ \n\)
2683
+ # End of non-capturing group.
2684
+ )
2685
+ """
2628
2686
  cks = []
2629
- # NOTE: we aren't using re.S here because we actually are
2630
- # taking advantage of each CHECK constraint being all on one
2631
- # line in the table definition in order to delineate. This
2632
- # necessarily makes assumptions as to how the CREATE TABLE
2633
- # was emitted.
2634
-
2635
- for match in re.finditer(CHECK_PATTERN, table_data or "", re.I):
2687
+ for match in re.finditer(
2688
+ CHECK_PATTERN, table_data or "", re.I | re.S | re.VERBOSE
2689
+ ):
2636
2690
  name = match.group(1)
2637
2691
 
2638
2692
  if name:
@@ -52,11 +52,11 @@ used. Double backslashes are probably needed::
52
52
  e = create_engine('sqlite:///C:\\path\\to\\database.db')
53
53
 
54
54
  To use sqlite ``:memory:`` database specify it as the filename using
55
- ``sqlite://:memory:``. It's also the default if no filepath is
55
+ ``sqlite:///:memory:``. It's also the default if no filepath is
56
56
  present, specifying only ``sqlite://`` and nothing else::
57
57
 
58
- # in-memory database
59
- e = create_engine('sqlite://:memory:')
58
+ # in-memory database (note three slashes)
59
+ e = create_engine('sqlite:///:memory:')
60
60
  # also in-memory database
61
61
  e2 = create_engine('sqlite://')
62
62
 
@@ -55,6 +55,7 @@ from .. import util
55
55
  from ..sql import operators
56
56
  from ..sql import schema as sa_schema
57
57
  from ..sql.cache_key import _ad_hoc_cache_key_from_args
58
+ from ..sql.elements import quoted_name
58
59
  from ..sql.elements import TextClause
59
60
  from ..sql.type_api import TypeEngine
60
61
  from ..sql.visitors import InternalTraversal
@@ -89,8 +90,16 @@ def cache(
89
90
  exclude = {"info_cache", "unreflectable"}
90
91
  key = (
91
92
  fn.__name__,
92
- tuple(a for a in args if isinstance(a, str)),
93
- tuple((k, v) for k, v in kw.items() if k not in exclude),
93
+ tuple(
94
+ (str(a), a.quote) if isinstance(a, quoted_name) else a
95
+ for a in args
96
+ if isinstance(a, str)
97
+ ),
98
+ tuple(
99
+ (k, (str(v), v.quote) if isinstance(v, quoted_name) else v)
100
+ for k, v in kw.items()
101
+ if k not in exclude
102
+ ),
94
103
  )
95
104
  ret: _R = info_cache.get(key)
96
105
  if ret is None:
@@ -287,8 +287,9 @@ class _ModuleMarker(ClsRegistryToken):
287
287
 
288
288
  def _remove_item(self, name: str) -> None:
289
289
  self.contents.pop(name, None)
290
- if not self.contents and self.parent is not None:
291
- self.parent._remove_item(self.name)
290
+ if not self.contents:
291
+ if self.parent is not None:
292
+ self.parent._remove_item(self.name)
292
293
  _registries.discard(self)
293
294
 
294
295
  def resolve_attr(self, key: str) -> Union[_ModNS, Type[Any]]:
@@ -431,7 +431,7 @@ class _ImperativeMapperConfig(_MapperConfig):
431
431
  class _CollectedAnnotation(NamedTuple):
432
432
  raw_annotation: _AnnotationScanType
433
433
  mapped_container: Optional[Type[Mapped[Any]]]
434
- extracted_mapped_annotation: Union[Type[Any], str]
434
+ extracted_mapped_annotation: Union[_AnnotationScanType, str]
435
435
  is_dataclass: bool
436
436
  attr_value: Any
437
437
  originating_module: str
sqlalchemy/orm/util.py CHANGED
@@ -89,6 +89,7 @@ from ..util.typing import (
89
89
  de_stringify_union_elements as _de_stringify_union_elements,
90
90
  )
91
91
  from ..util.typing import eval_name_only as _eval_name_only
92
+ from ..util.typing import fixup_container_fwd_refs
92
93
  from ..util.typing import is_origin_of_cls
93
94
  from ..util.typing import Literal
94
95
  from ..util.typing import Protocol
@@ -2321,7 +2322,7 @@ def _extract_mapped_subtype(
2321
2322
  is_dataclass_field: bool,
2322
2323
  expect_mapped: bool = True,
2323
2324
  raiseerr: bool = True,
2324
- ) -> Optional[Tuple[Union[type, str], Optional[type]]]:
2325
+ ) -> Optional[Tuple[Union[_AnnotationScanType, str], Optional[type]]]:
2325
2326
  """given an annotation, figure out if it's ``Mapped[something]`` and if
2326
2327
  so, return the ``something`` part.
2327
2328
 
@@ -2407,7 +2408,11 @@ def _extract_mapped_subtype(
2407
2408
  "Expected sub-type for Mapped[] annotation"
2408
2409
  )
2409
2410
 
2410
- return annotated.__args__[0], annotated.__origin__
2411
+ return (
2412
+ # fix dict/list/set args to be ForwardRef, see #11814
2413
+ fixup_container_fwd_refs(annotated.__args__[0]),
2414
+ annotated.__origin__,
2415
+ )
2411
2416
 
2412
2417
 
2413
2418
  def _mapper_property_as_plain_name(prop: Type[Any]) -> str:
@@ -5315,7 +5315,14 @@ class AnnotatedColumnElement(Annotated):
5315
5315
 
5316
5316
  def _with_annotations(self, values):
5317
5317
  clone = super()._with_annotations(values)
5318
- clone.__dict__.pop("comparator", None)
5318
+ for attr in (
5319
+ "comparator",
5320
+ "_proxy_key",
5321
+ "_tq_key_label",
5322
+ "_tq_label",
5323
+ "_non_anon_label",
5324
+ ):
5325
+ clone.__dict__.pop(attr, None)
5319
5326
  return clone
5320
5327
 
5321
5328
  @util.memoized_property
sqlalchemy/sql/schema.py CHANGED
@@ -1434,7 +1434,7 @@ class Table(
1434
1434
 
1435
1435
  args = []
1436
1436
  for col in self.columns:
1437
- args.append(col._copy(schema=actual_schema))
1437
+ args.append(col._copy(schema=actual_schema, _to_metadata=metadata))
1438
1438
  table = Table(
1439
1439
  name,
1440
1440
  metadata,
@@ -2475,6 +2475,8 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]):
2475
2475
  server_onupdate = self.server_onupdate
2476
2476
  if isinstance(server_default, (Computed, Identity)):
2477
2477
  # TODO: likely should be copied in all cases
2478
+ # TODO: if a Sequence, we would need to transfer the Sequence
2479
+ # .metadata as well
2478
2480
  args.append(server_default._copy(**kw))
2479
2481
  server_default = server_onupdate = None
2480
2482
 
@@ -473,14 +473,25 @@ class HasHints:
473
473
  ("_hints", InternalTraversal.dp_table_hint_list),
474
474
  ]
475
475
 
476
+ @_generative
476
477
  def with_statement_hint(self, text: str, dialect_name: str = "*") -> Self:
477
478
  """Add a statement hint to this :class:`_expression.Select` or
478
479
  other selectable object.
479
480
 
480
- This method is similar to :meth:`_expression.Select.with_hint`
481
- except that
482
- it does not require an individual table, and instead applies to the
483
- statement as a whole.
481
+ .. tip::
482
+
483
+ :meth:`_expression.Select.with_statement_hint` generally adds hints
484
+ **at the trailing end** of a SELECT statement. To place
485
+ dialect-specific hints such as optimizer hints at the **front** of
486
+ the SELECT statement after the SELECT keyword, use the
487
+ :meth:`_expression.Select.prefix_with` method for an open-ended
488
+ space, or for table-specific hints the
489
+ :meth:`_expression.Select.with_hint` may be used, which places
490
+ hints in a dialect-specific location.
491
+
492
+ This method is similar to :meth:`_expression.Select.with_hint` except
493
+ that it does not require an individual table, and instead applies to
494
+ the statement as a whole.
484
495
 
485
496
  Hints here are specific to the backend database and may include
486
497
  directives such as isolation levels, file directives, fetch directives,
@@ -492,7 +503,7 @@ class HasHints:
492
503
 
493
504
  :meth:`_expression.Select.prefix_with` - generic SELECT prefixing
494
505
  which also can suit some database-specific HINT syntaxes such as
495
- MySQL optimizer hints
506
+ MySQL or Oracle optimizer hints
496
507
 
497
508
  """
498
509
  return self._with_hint(None, text, dialect_name)
@@ -508,6 +519,17 @@ class HasHints:
508
519
  selectable to this :class:`_expression.Select` or other selectable
509
520
  object.
510
521
 
522
+ .. tip::
523
+
524
+ The :meth:`_expression.Select.with_hint` method adds hints that are
525
+ **specific to a single table** to a statement, in a location that
526
+ is **dialect-specific**. To add generic optimizer hints to the
527
+ **beginning** of a statement ahead of the SELECT keyword such as
528
+ for MySQL or Oracle, use the :meth:`_expression.Select.prefix_with`
529
+ method. To add optimizer hints to the **end** of a statement such
530
+ as for PostgreSQL, use the
531
+ :meth:`_expression.Select.with_statement_hint` method.
532
+
511
533
  The text of the hint is rendered in the appropriate
512
534
  location for the database backend in use, relative
513
535
  to the given :class:`_schema.Table` or :class:`_expression.Alias`
@@ -537,6 +559,10 @@ class HasHints:
537
559
 
538
560
  :meth:`_expression.Select.with_statement_hint`
539
561
 
562
+ :meth:`_expression.Select.prefix_with` - generic SELECT prefixing
563
+ which also can suit some database-specific HINT syntaxes such as
564
+ MySQL or Oracle optimizer hints
565
+
540
566
  """
541
567
 
542
568
  return self._with_hint(selectable, text, dialect_name)
@@ -5793,22 +5819,33 @@ class Select(
5793
5819
  )
5794
5820
  return woc
5795
5821
 
5796
- # START OVERLOADED FUNCTIONS self.with_only_columns Select 8
5822
+ # START OVERLOADED FUNCTIONS self.with_only_columns Select 1-8 ", *, maintain_column_froms: bool =..." # noqa: E501
5797
5823
 
5798
5824
  # code within this block is **programmatically,
5799
- # statically generated** by tools/generate_sel_v1_overloads.py
5825
+ # statically generated** by tools/generate_tuple_map_overloads.py
5800
5826
 
5801
5827
  @overload
5802
- def with_only_columns(self, __ent0: _TCCA[_T0]) -> Select[Tuple[_T0]]: ...
5828
+ def with_only_columns(
5829
+ self, __ent0: _TCCA[_T0], *, maintain_column_froms: bool = ...
5830
+ ) -> Select[Tuple[_T0]]: ...
5803
5831
 
5804
5832
  @overload
5805
5833
  def with_only_columns(
5806
- self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1]
5834
+ self,
5835
+ __ent0: _TCCA[_T0],
5836
+ __ent1: _TCCA[_T1],
5837
+ *,
5838
+ maintain_column_froms: bool = ...,
5807
5839
  ) -> Select[Tuple[_T0, _T1]]: ...
5808
5840
 
5809
5841
  @overload
5810
5842
  def with_only_columns(
5811
- self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2]
5843
+ self,
5844
+ __ent0: _TCCA[_T0],
5845
+ __ent1: _TCCA[_T1],
5846
+ __ent2: _TCCA[_T2],
5847
+ *,
5848
+ maintain_column_froms: bool = ...,
5812
5849
  ) -> Select[Tuple[_T0, _T1, _T2]]: ...
5813
5850
 
5814
5851
  @overload
@@ -5818,6 +5855,8 @@ class Select(
5818
5855
  __ent1: _TCCA[_T1],
5819
5856
  __ent2: _TCCA[_T2],
5820
5857
  __ent3: _TCCA[_T3],
5858
+ *,
5859
+ maintain_column_froms: bool = ...,
5821
5860
  ) -> Select[Tuple[_T0, _T1, _T2, _T3]]: ...
5822
5861
 
5823
5862
  @overload
@@ -5828,6 +5867,8 @@ class Select(
5828
5867
  __ent2: _TCCA[_T2],
5829
5868
  __ent3: _TCCA[_T3],
5830
5869
  __ent4: _TCCA[_T4],
5870
+ *,
5871
+ maintain_column_froms: bool = ...,
5831
5872
  ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4]]: ...
5832
5873
 
5833
5874
  @overload
@@ -5839,6 +5880,8 @@ class Select(
5839
5880
  __ent3: _TCCA[_T3],
5840
5881
  __ent4: _TCCA[_T4],
5841
5882
  __ent5: _TCCA[_T5],
5883
+ *,
5884
+ maintain_column_froms: bool = ...,
5842
5885
  ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ...
5843
5886
 
5844
5887
  @overload
@@ -5851,6 +5894,8 @@ class Select(
5851
5894
  __ent4: _TCCA[_T4],
5852
5895
  __ent5: _TCCA[_T5],
5853
5896
  __ent6: _TCCA[_T6],
5897
+ *,
5898
+ maintain_column_froms: bool = ...,
5854
5899
  ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ...
5855
5900
 
5856
5901
  @overload
@@ -5864,6 +5909,8 @@ class Select(
5864
5909
  __ent5: _TCCA[_T5],
5865
5910
  __ent6: _TCCA[_T6],
5866
5911
  __ent7: _TCCA[_T7],
5912
+ *,
5913
+ maintain_column_froms: bool = ...,
5867
5914
  ) -> Select[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]: ...
5868
5915
 
5869
5916
  # END OVERLOADED FUNCTIONS self.with_only_columns
@@ -1085,6 +1085,11 @@ class SchemaType(SchemaEventTarget, TypeEngineMixin):
1085
1085
  return self.adapt(
1086
1086
  cast("Type[TypeEngine[Any]]", self.__class__),
1087
1087
  _create_events=True,
1088
+ metadata=(
1089
+ kw.get("_to_metadata", self.metadata)
1090
+ if self.metadata is not None
1091
+ else None
1092
+ ),
1088
1093
  )
1089
1094
 
1090
1095
  @overload
@@ -1908,6 +1913,13 @@ class Boolean(SchemaType, Emulated, TypeEngine[bool]):
1908
1913
  if _adapted_from:
1909
1914
  self.dispatch = self.dispatch._join(_adapted_from.dispatch)
1910
1915
 
1916
+ def copy(self, **kw):
1917
+ # override SchemaType.copy() to not include to_metadata logic
1918
+ return self.adapt(
1919
+ cast("Type[TypeEngine[Any]]", self.__class__),
1920
+ _create_events=True,
1921
+ )
1922
+
1911
1923
  def _should_create_constraint(self, compiler, **kw):
1912
1924
  if not self._is_impl_for_variant(compiler.dialect, kw):
1913
1925
  return False
@@ -362,7 +362,7 @@ def update_db_opts(db_url, db_opts, options):
362
362
  def post_configure_engine(url, engine, follower_ident):
363
363
  """Perform extra steps after configuring an engine for testing.
364
364
 
365
- (For the internal dialects, currently only used by sqlite, oracle)
365
+ (For the internal dialects, currently only used by sqlite, oracle, mssql)
366
366
  """
367
367
 
368
368
 
@@ -1093,6 +1093,11 @@ class SuiteRequirements(Requirements):
1093
1093
 
1094
1094
  return exclusions.only_if(go)
1095
1095
 
1096
+ @property
1097
+ def array_type(self):
1098
+ """Target platform implements a native ARRAY type"""
1099
+ return exclusions.closed()
1100
+
1096
1101
  @property
1097
1102
  def json_type(self):
1098
1103
  """target platform implements a native JSON type."""
sqlalchemy/util/typing.py CHANGED
@@ -188,9 +188,51 @@ def de_stringify_annotation(
188
188
  )
189
189
 
190
190
  return _copy_generic_annotation_with(annotation, elements)
191
+
191
192
  return annotation # type: ignore
192
193
 
193
194
 
195
+ def fixup_container_fwd_refs(
196
+ type_: _AnnotationScanType,
197
+ ) -> _AnnotationScanType:
198
+ """Correct dict['x', 'y'] into dict[ForwardRef('x'), ForwardRef('y')]
199
+ and similar for list, set
200
+
201
+ """
202
+
203
+ if (
204
+ is_generic(type_)
205
+ and typing_get_origin(type_)
206
+ in (
207
+ dict,
208
+ set,
209
+ list,
210
+ collections_abc.MutableSet,
211
+ collections_abc.MutableMapping,
212
+ collections_abc.MutableSequence,
213
+ collections_abc.Mapping,
214
+ collections_abc.Sequence,
215
+ )
216
+ # fight, kick and scream to struggle to tell the difference between
217
+ # dict[] and typing.Dict[] which DO NOT compare the same and DO NOT
218
+ # behave the same yet there is NO WAY to distinguish between which type
219
+ # it is using public attributes
220
+ and not re.match(
221
+ "typing.(?:Dict|List|Set|.*Mapping|.*Sequence|.*Set)", repr(type_)
222
+ )
223
+ ):
224
+ # compat with py3.10 and earlier
225
+ return typing_get_origin(type_).__class_getitem__( # type: ignore
226
+ tuple(
227
+ [
228
+ ForwardRef(elem) if isinstance(elem, str) else elem
229
+ for elem in typing_get_args(type_)
230
+ ]
231
+ )
232
+ )
233
+ return type_
234
+
235
+
194
236
  def _copy_generic_annotation_with(
195
237
  annotation: GenericProtocol[_T], elements: Tuple[_AnnotationScanType, ...]
196
238
  ) -> Type[_T]: