SQLAlchemy 2.1.0b2__cp313-cp313t-win_arm64.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.
Files changed (270) hide show
  1. sqlalchemy/__init__.py +298 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +171 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +30 -0
  8. sqlalchemy/dialects/mssql/__init__.py +89 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4166 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +220 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +698 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +226 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +214 -0
  21. sqlalchemy/dialects/mysql/base.py +3877 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  23. sqlalchemy/dialects/mysql/dml.py +279 -0
  24. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  25. sqlalchemy/dialects/mysql/expression.py +146 -0
  26. sqlalchemy/dialects/mysql/json.py +92 -0
  27. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  28. sqlalchemy/dialects/mysql/mariadbconnector.py +330 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +296 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +312 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +157 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +156 -0
  34. sqlalchemy/dialects/mysql/reflection.py +724 -0
  35. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  36. sqlalchemy/dialects/mysql/types.py +845 -0
  37. sqlalchemy/dialects/oracle/__init__.py +85 -0
  38. sqlalchemy/dialects/oracle/base.py +3977 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1601 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +158 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +909 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +368 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +171 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +229 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1323 -0
  50. sqlalchemy/dialects/postgresql/base.py +5789 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +593 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +423 -0
  55. sqlalchemy/dialects/postgresql/json.py +408 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +521 -0
  57. sqlalchemy/dialects/postgresql/operators.py +130 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +670 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +344 -0
  60. sqlalchemy/dialects/postgresql/provision.py +184 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +799 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +321 -0
  68. sqlalchemy/dialects/sqlite/base.py +3063 -0
  69. sqlalchemy/dialects/sqlite/dml.py +279 -0
  70. sqlalchemy/dialects/sqlite/json.py +100 -0
  71. sqlalchemy/dialects/sqlite/provision.py +229 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +161 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +754 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp313t-win_arm64.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp313t-win_arm64.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +633 -0
  80. sqlalchemy/engine/_row_cy.cp313t-win_arm64.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp313t-win_arm64.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3354 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2421 -0
  88. sqlalchemy/engine/default.py +2402 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3495 -0
  91. sqlalchemy/engine/mock.py +134 -0
  92. sqlalchemy/engine/processors.py +82 -0
  93. sqlalchemy/engine/reflection.py +2100 -0
  94. sqlalchemy/engine/result.py +1966 -0
  95. sqlalchemy/engine/row.py +397 -0
  96. sqlalchemy/engine/strategies.py +16 -0
  97. sqlalchemy/engine/url.py +922 -0
  98. sqlalchemy/engine/util.py +156 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +674 -0
  102. sqlalchemy/event/base.py +472 -0
  103. sqlalchemy/event/legacy.py +258 -0
  104. sqlalchemy/event/registry.py +390 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +922 -0
  107. sqlalchemy/ext/__init__.py +11 -0
  108. sqlalchemy/ext/associationproxy.py +2072 -0
  109. sqlalchemy/ext/asyncio/__init__.py +29 -0
  110. sqlalchemy/ext/asyncio/base.py +281 -0
  111. sqlalchemy/ext/asyncio/engine.py +1487 -0
  112. sqlalchemy/ext/asyncio/exc.py +21 -0
  113. sqlalchemy/ext/asyncio/result.py +994 -0
  114. sqlalchemy/ext/asyncio/scoping.py +1679 -0
  115. sqlalchemy/ext/asyncio/session.py +2007 -0
  116. sqlalchemy/ext/automap.py +1701 -0
  117. sqlalchemy/ext/baked.py +559 -0
  118. sqlalchemy/ext/compiler.py +600 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +560 -0
  121. sqlalchemy/ext/horizontal_shard.py +481 -0
  122. sqlalchemy/ext/hybrid.py +1877 -0
  123. sqlalchemy/ext/indexable.py +364 -0
  124. sqlalchemy/ext/instrumentation.py +450 -0
  125. sqlalchemy/ext/mutable.py +1081 -0
  126. sqlalchemy/ext/orderinglist.py +439 -0
  127. sqlalchemy/ext/serializer.py +185 -0
  128. sqlalchemy/future/__init__.py +16 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +174 -0
  131. sqlalchemy/log.py +283 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +179 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +976 -0
  137. sqlalchemy/orm/bulk_persistence.py +2152 -0
  138. sqlalchemy/orm/clsregistry.py +582 -0
  139. sqlalchemy/orm/collections.py +1568 -0
  140. sqlalchemy/orm/context.py +3471 -0
  141. sqlalchemy/orm/decl_api.py +2280 -0
  142. sqlalchemy/orm/decl_base.py +2309 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +307 -0
  146. sqlalchemy/orm/evaluator.py +379 -0
  147. sqlalchemy/orm/events.py +3386 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +746 -0
  151. sqlalchemy/orm/interfaces.py +1589 -0
  152. sqlalchemy/orm/loading.py +1684 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4411 -0
  155. sqlalchemy/orm/path_registry.py +829 -0
  156. sqlalchemy/orm/persistence.py +1789 -0
  157. sqlalchemy/orm/properties.py +973 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3570 -0
  160. sqlalchemy/orm/scoping.py +2232 -0
  161. sqlalchemy/orm/session.py +5403 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3492 -0
  165. sqlalchemy/orm/strategy_options.py +2562 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +798 -0
  168. sqlalchemy/orm/util.py +2438 -0
  169. sqlalchemy/orm/writeonly.py +694 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1522 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +582 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +74 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +397 -0
  178. sqlalchemy/sql/_dml_constructors.py +132 -0
  179. sqlalchemy/sql/_elements_constructors.py +2164 -0
  180. sqlalchemy/sql/_orm_types.py +20 -0
  181. sqlalchemy/sql/_selectable_constructors.py +840 -0
  182. sqlalchemy/sql/_typing.py +487 -0
  183. sqlalchemy/sql/_util_cy.cp313t-win_arm64.pyd +0 -0
  184. sqlalchemy/sql/_util_cy.py +127 -0
  185. sqlalchemy/sql/annotation.py +590 -0
  186. sqlalchemy/sql/base.py +2699 -0
  187. sqlalchemy/sql/cache_key.py +1066 -0
  188. sqlalchemy/sql/coercions.py +1373 -0
  189. sqlalchemy/sql/compiler.py +8327 -0
  190. sqlalchemy/sql/crud.py +1815 -0
  191. sqlalchemy/sql/ddl.py +1928 -0
  192. sqlalchemy/sql/default_comparator.py +654 -0
  193. sqlalchemy/sql/dml.py +1977 -0
  194. sqlalchemy/sql/elements.py +6033 -0
  195. sqlalchemy/sql/events.py +458 -0
  196. sqlalchemy/sql/expression.py +172 -0
  197. sqlalchemy/sql/functions.py +2305 -0
  198. sqlalchemy/sql/lambdas.py +1443 -0
  199. sqlalchemy/sql/naming.py +209 -0
  200. sqlalchemy/sql/operators.py +2897 -0
  201. sqlalchemy/sql/roles.py +332 -0
  202. sqlalchemy/sql/schema.py +6703 -0
  203. sqlalchemy/sql/selectable.py +7553 -0
  204. sqlalchemy/sql/sqltypes.py +4093 -0
  205. sqlalchemy/sql/traversals.py +1042 -0
  206. sqlalchemy/sql/type_api.py +2446 -0
  207. sqlalchemy/sql/util.py +1495 -0
  208. sqlalchemy/sql/visitors.py +1157 -0
  209. sqlalchemy/testing/__init__.py +96 -0
  210. sqlalchemy/testing/assertions.py +1007 -0
  211. sqlalchemy/testing/assertsql.py +519 -0
  212. sqlalchemy/testing/asyncio.py +128 -0
  213. sqlalchemy/testing/config.py +440 -0
  214. sqlalchemy/testing/engines.py +483 -0
  215. sqlalchemy/testing/entities.py +117 -0
  216. sqlalchemy/testing/exclusions.py +476 -0
  217. sqlalchemy/testing/fixtures/__init__.py +30 -0
  218. sqlalchemy/testing/fixtures/base.py +384 -0
  219. sqlalchemy/testing/fixtures/mypy.py +247 -0
  220. sqlalchemy/testing/fixtures/orm.py +227 -0
  221. sqlalchemy/testing/fixtures/sql.py +538 -0
  222. sqlalchemy/testing/pickleable.py +155 -0
  223. sqlalchemy/testing/plugin/__init__.py +6 -0
  224. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  225. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  226. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  227. sqlalchemy/testing/profiling.py +329 -0
  228. sqlalchemy/testing/provision.py +613 -0
  229. sqlalchemy/testing/requirements.py +1978 -0
  230. sqlalchemy/testing/schema.py +198 -0
  231. sqlalchemy/testing/suite/__init__.py +19 -0
  232. sqlalchemy/testing/suite/test_cte.py +237 -0
  233. sqlalchemy/testing/suite/test_ddl.py +420 -0
  234. sqlalchemy/testing/suite/test_dialect.py +776 -0
  235. sqlalchemy/testing/suite/test_insert.py +630 -0
  236. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  237. sqlalchemy/testing/suite/test_results.py +660 -0
  238. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  239. sqlalchemy/testing/suite/test_select.py +2112 -0
  240. sqlalchemy/testing/suite/test_sequence.py +317 -0
  241. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  242. sqlalchemy/testing/suite/test_types.py +2271 -0
  243. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  244. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  245. sqlalchemy/testing/util.py +535 -0
  246. sqlalchemy/testing/warnings.py +52 -0
  247. sqlalchemy/types.py +76 -0
  248. sqlalchemy/util/__init__.py +158 -0
  249. sqlalchemy/util/_collections.py +688 -0
  250. sqlalchemy/util/_collections_cy.cp313t-win_arm64.pyd +0 -0
  251. sqlalchemy/util/_collections_cy.pxd +8 -0
  252. sqlalchemy/util/_collections_cy.py +516 -0
  253. sqlalchemy/util/_has_cython.py +46 -0
  254. sqlalchemy/util/_immutabledict_cy.cp313t-win_arm64.pyd +0 -0
  255. sqlalchemy/util/_immutabledict_cy.py +240 -0
  256. sqlalchemy/util/compat.py +299 -0
  257. sqlalchemy/util/concurrency.py +322 -0
  258. sqlalchemy/util/cython.py +79 -0
  259. sqlalchemy/util/deprecations.py +401 -0
  260. sqlalchemy/util/langhelpers.py +2320 -0
  261. sqlalchemy/util/preloaded.py +152 -0
  262. sqlalchemy/util/queue.py +304 -0
  263. sqlalchemy/util/tool_support.py +201 -0
  264. sqlalchemy/util/topological.py +120 -0
  265. sqlalchemy/util/typing.py +711 -0
  266. sqlalchemy-2.1.0b2.dist-info/METADATA +269 -0
  267. sqlalchemy-2.1.0b2.dist-info/RECORD +270 -0
  268. sqlalchemy-2.1.0b2.dist-info/WHEEL +5 -0
  269. sqlalchemy-2.1.0b2.dist-info/licenses/LICENSE +19 -0
  270. sqlalchemy-2.1.0b2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,327 @@
1
+ # dialects/postgresql/bitstring.py
2
+ # Copyright (C) 2013-2026 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+ from __future__ import annotations
8
+
9
+ import math
10
+ from typing import Any
11
+ from typing import cast
12
+ from typing import Literal
13
+ from typing import SupportsIndex
14
+
15
+
16
+ class BitString(str):
17
+ """Represent a PostgreSQL bit string in python.
18
+
19
+ This object is used by the :class:`_postgresql.BIT` type when returning
20
+ values. :class:`_postgresql.BitString` values may also be constructed
21
+ directly and used with :class:`_postgresql.BIT` columns::
22
+
23
+ from sqlalchemy.dialects.postgresql import BitString
24
+
25
+ with engine.connect() as conn:
26
+ conn.execute(table.insert(), {"data": BitString("011001101")})
27
+
28
+ .. versionadded:: 2.1
29
+
30
+ """
31
+
32
+ _DIGITS = frozenset("01")
33
+
34
+ def __new__(cls, _value: str, _check: bool = True) -> BitString:
35
+ if isinstance(_value, BitString):
36
+ return _value
37
+ elif _check and cls._DIGITS.union(_value) > cls._DIGITS:
38
+ raise ValueError("BitString must only contain '0' and '1' chars")
39
+ else:
40
+ return super().__new__(cls, _value)
41
+
42
+ @classmethod
43
+ def from_int(cls, value: int, length: int) -> BitString:
44
+ """Returns a BitString consisting of the bits in the integer ``value``.
45
+ A ``ValueError`` is raised if ``value`` is not a non-negative integer.
46
+
47
+ If the provided ``value`` can not be represented in a bit string
48
+ of at most ``length``, a ``ValueError`` will be raised. The bitstring
49
+ will be padded on the left by ``'0'`` to bits to produce a
50
+ bitstring of the desired length.
51
+ """
52
+ if value < 0:
53
+ raise ValueError("value must be non-negative")
54
+ if length < 0:
55
+ raise ValueError("length must be non-negative")
56
+
57
+ template_str = f"{{0:0{length}b}}" if length > 0 else ""
58
+ r = template_str.format(value)
59
+
60
+ if (length == 0 and value > 0) or len(r) > length:
61
+ raise ValueError(
62
+ f"Cannot encode {value} as a BitString of length {length}"
63
+ )
64
+
65
+ return cls(r)
66
+
67
+ @classmethod
68
+ def from_bytes(cls, value: bytes, length: int = -1) -> BitString:
69
+ """Returns a ``BitString`` consisting of the bits in the given
70
+ ``value`` bytes.
71
+
72
+ If ``length`` is provided, then the length of the provided string
73
+ will be exactly ``length``, with ``'0'`` bits inserted at the left of
74
+ the string in order to produce a value of the required length.
75
+ If the bits obtained by omitting the leading ``'0'`` bits of ``value``
76
+ cannot be represented in a string of this length a ``ValueError``
77
+ will be raised.
78
+ """
79
+ str_v: str = "".join(f"{int(c):08b}" for c in value)
80
+ if length >= 0:
81
+ str_v = str_v.lstrip("0")
82
+
83
+ if len(str_v) > length:
84
+ raise ValueError(
85
+ f"Cannot encode {value!r} as a BitString of "
86
+ f"length {length}"
87
+ )
88
+ str_v = str_v.zfill(length)
89
+
90
+ return cls(str_v)
91
+
92
+ def get_bit(self, index: int) -> Literal["0", "1"]:
93
+ """Returns the value of the flag at the given
94
+ index::
95
+
96
+ BitString("0101").get_flag(4) == "1"
97
+ """
98
+ return cast(Literal["0", "1"], super().__getitem__(index))
99
+
100
+ @property
101
+ def bit_length(self) -> int:
102
+ return len(self)
103
+
104
+ @property
105
+ def octet_length(self) -> int:
106
+ return math.ceil(len(self) / 8)
107
+
108
+ def has_bit(self, index: int) -> bool:
109
+ return self.get_bit(index) == "1"
110
+
111
+ def set_bit(
112
+ self, index: int, value: bool | int | Literal["0", "1"]
113
+ ) -> BitString:
114
+ """Set the bit at index to the given value.
115
+
116
+ If value is an int, then it is considered to be '1' iff nonzero.
117
+ """
118
+ if index < 0 or index >= len(self):
119
+ raise IndexError("BitString index out of range")
120
+
121
+ if isinstance(value, (bool, int)):
122
+ value = "1" if value else "0"
123
+
124
+ if self.get_bit(index) == value:
125
+ return self
126
+
127
+ return BitString(
128
+ "".join([self[:index], value, self[index + 1 :]]), False
129
+ )
130
+
131
+ def lstrip(self, char: str | None = None) -> BitString:
132
+ """Returns a copy of the BitString with leading characters removed.
133
+
134
+ If omitted or None, 'chars' defaults '0'::
135
+
136
+ BitString("00010101000").lstrip() == BitString("00010101")
137
+ BitString("11110101111").lstrip("1") == BitString("1111010")
138
+ """
139
+ if char is None:
140
+ char = "0"
141
+ return BitString(super().lstrip(char), False)
142
+
143
+ def rstrip(self, char: str | None = "0") -> BitString:
144
+ """Returns a copy of the BitString with trailing characters removed.
145
+
146
+ If omitted or None, ``'char'`` defaults to "0"::
147
+
148
+ BitString("00010101000").rstrip() == BitString("10101000")
149
+ BitString("11110101111").rstrip("1") == BitString("10101111")
150
+ """
151
+ if char is None:
152
+ char = "0"
153
+ return BitString(super().rstrip(char), False)
154
+
155
+ def strip(self, char: str | None = "0") -> BitString:
156
+ """Returns a copy of the BitString with both leading and trailing
157
+ characters removed.
158
+ If omitted or None, ``'char'`` defaults to ``"0"``::
159
+
160
+ BitString("00010101000").rstrip() == BitString("10101")
161
+ BitString("11110101111").rstrip("1") == BitString("1010")
162
+ """
163
+ if char is None:
164
+ char = "0"
165
+ return BitString(super().strip(char))
166
+
167
+ def removeprefix(self, prefix: str, /) -> BitString:
168
+ return BitString(super().removeprefix(prefix), False)
169
+
170
+ def removesuffix(self, suffix: str, /) -> BitString:
171
+ return BitString(super().removesuffix(suffix), False)
172
+
173
+ def replace(
174
+ self,
175
+ old: str,
176
+ new: str,
177
+ count: SupportsIndex = -1,
178
+ ) -> BitString:
179
+ new = BitString(new)
180
+ return BitString(super().replace(old, new, count), False)
181
+
182
+ def split(
183
+ self,
184
+ sep: str | None = None,
185
+ maxsplit: SupportsIndex = -1,
186
+ ) -> list[str]:
187
+ return [BitString(word) for word in super().split(sep, maxsplit)]
188
+
189
+ def zfill(self, width: SupportsIndex) -> BitString:
190
+ return BitString(super().zfill(width), False)
191
+
192
+ def __repr__(self) -> str:
193
+ return f'BitString("{self.__str__()}")'
194
+
195
+ def __int__(self) -> int:
196
+ return int(self, 2) if self else 0
197
+
198
+ def to_bytes(self, length: int = -1) -> bytes:
199
+ return int(self).to_bytes(
200
+ length if length >= 0 else self.octet_length, byteorder="big"
201
+ )
202
+
203
+ def __bytes__(self) -> bytes:
204
+ return self.to_bytes()
205
+
206
+ def __getitem__(
207
+ self, key: SupportsIndex | slice[Any, Any, Any]
208
+ ) -> BitString:
209
+ return BitString(super().__getitem__(key), False)
210
+
211
+ def __add__(self, o: str) -> BitString:
212
+ """Return self + o"""
213
+ if not isinstance(o, str):
214
+ raise TypeError(
215
+ f"Can only concatenate str (not '{type(self)}') to BitString"
216
+ )
217
+ return BitString("".join([self, o]))
218
+
219
+ def __radd__(self, o: str) -> BitString:
220
+ if not isinstance(o, str):
221
+ raise TypeError(
222
+ f"Can only concatenate str (not '{type(self)}') to BitString"
223
+ )
224
+ return BitString("".join([o, self]))
225
+
226
+ def __lshift__(self, amount: int) -> BitString:
227
+ """Shifts each the bitstring to the left by the given amount.
228
+ String length is preserved::
229
+
230
+ BitString("000101") << 1 == BitString("001010")
231
+ """
232
+ return BitString(
233
+ "".join([self, *("0" for _ in range(amount))])[-len(self) :], False
234
+ )
235
+
236
+ def __rshift__(self, amount: int) -> BitString:
237
+ """Shifts each bit in the bitstring to the right by the given amount.
238
+ String length is preserved::
239
+
240
+ BitString("101") >> 1 == BitString("010")
241
+ """
242
+ return BitString(self[:-amount], False).zfill(width=len(self))
243
+
244
+ def __invert__(self) -> BitString:
245
+ """Inverts (~) each bit in the
246
+ bitstring::
247
+
248
+ ~BitString("01010") == BitString("10101")
249
+ """
250
+ return BitString("".join("1" if x == "0" else "0" for x in self))
251
+
252
+ def __and__(self, o: str) -> BitString:
253
+ """Performs a bitwise and (``&``) with the given operand.
254
+ A ``ValueError`` is raised if the operand is not the same length.
255
+
256
+ e.g.::
257
+
258
+ BitString("011") & BitString("011") == BitString("010")
259
+ """
260
+
261
+ if not isinstance(o, str):
262
+ return NotImplemented
263
+ o = BitString(o)
264
+ if len(self) != len(o):
265
+ raise ValueError("Operands must be the same length")
266
+
267
+ return BitString(
268
+ "".join(
269
+ "1" if (x == "1" and y == "1") else "0"
270
+ for x, y in zip(self, o)
271
+ ),
272
+ False,
273
+ )
274
+
275
+ def __or__(self, o: str) -> BitString:
276
+ """Performs a bitwise or (``|``) with the given operand.
277
+ A ``ValueError`` is raised if the operand is not the same length.
278
+
279
+ e.g.::
280
+
281
+ BitString("011") | BitString("010") == BitString("011")
282
+ """
283
+ if not isinstance(o, str):
284
+ return NotImplemented
285
+
286
+ if len(self) != len(o):
287
+ raise ValueError("Operands must be the same length")
288
+
289
+ o = BitString(o)
290
+ return BitString(
291
+ "".join(
292
+ "1" if (x == "1" or y == "1") else "0"
293
+ for (x, y) in zip(self, o)
294
+ ),
295
+ False,
296
+ )
297
+
298
+ def __xor__(self, o: str) -> BitString:
299
+ """Performs a bitwise xor (``^``) with the given operand.
300
+ A ``ValueError`` is raised if the operand is not the same length.
301
+
302
+ e.g.::
303
+
304
+ BitString("011") ^ BitString("010") == BitString("001")
305
+ """
306
+
307
+ if not isinstance(o, BitString):
308
+ return NotImplemented
309
+
310
+ if len(self) != len(o):
311
+ raise ValueError("Operands must be the same length")
312
+
313
+ return BitString(
314
+ "".join(
315
+ (
316
+ "1"
317
+ if ((x == "1" and y == "0") or (x == "0" and y == "1"))
318
+ else "0"
319
+ )
320
+ for (x, y) in zip(self, o)
321
+ ),
322
+ False,
323
+ )
324
+
325
+ __rand__ = __and__
326
+ __ror__ = __or__
327
+ __rxor__ = __xor__
@@ -0,0 +1,360 @@
1
+ # dialects/postgresql/dml.py
2
+ # Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+ from typing import Dict
11
+ from typing import List
12
+ from typing import Optional
13
+ from typing import Union
14
+
15
+ from . import ext
16
+ from .._typing import _OnConflictConstraintT
17
+ from .._typing import _OnConflictIndexElementsT
18
+ from .._typing import _OnConflictIndexWhereT
19
+ from .._typing import _OnConflictSetT
20
+ from .._typing import _OnConflictWhereT
21
+ from ... import util
22
+ from ...sql import coercions
23
+ from ...sql import roles
24
+ from ...sql import schema
25
+ from ...sql._typing import _DMLTableArgument
26
+ from ...sql.base import _exclusive_against
27
+ from ...sql.base import ColumnCollection
28
+ from ...sql.base import ReadOnlyColumnCollection
29
+ from ...sql.base import SyntaxExtension
30
+ from ...sql.dml import _DMLColumnElement
31
+ from ...sql.dml import Insert as StandardInsert
32
+ from ...sql.elements import ClauseElement
33
+ from ...sql.elements import ColumnElement
34
+ from ...sql.elements import KeyedColumnElement
35
+ from ...sql.elements import TextClause
36
+ from ...sql.expression import alias
37
+ from ...sql.type_api import NULLTYPE
38
+ from ...sql.visitors import InternalTraversal
39
+ from ...util.typing import Self
40
+
41
+ __all__ = ("Insert", "insert")
42
+
43
+
44
+ def insert(table: _DMLTableArgument) -> Insert:
45
+ """Construct a PostgreSQL-specific variant :class:`_postgresql.Insert`
46
+ construct.
47
+
48
+ .. container:: inherited_member
49
+
50
+ The :func:`sqlalchemy.dialects.postgresql.insert` function creates
51
+ a :class:`sqlalchemy.dialects.postgresql.Insert`. This class is based
52
+ on the dialect-agnostic :class:`_sql.Insert` construct which may
53
+ be constructed using the :func:`_sql.insert` function in
54
+ SQLAlchemy Core.
55
+
56
+ The :class:`_postgresql.Insert` construct includes additional methods
57
+ :meth:`_postgresql.Insert.on_conflict_do_update`,
58
+ :meth:`_postgresql.Insert.on_conflict_do_nothing`.
59
+
60
+ """
61
+ return Insert(table)
62
+
63
+
64
+ class Insert(StandardInsert):
65
+ """PostgreSQL-specific implementation of INSERT.
66
+
67
+ Adds methods for PG-specific syntaxes such as ON CONFLICT.
68
+
69
+ The :class:`_postgresql.Insert` object is created using the
70
+ :func:`sqlalchemy.dialects.postgresql.insert` function.
71
+
72
+ """
73
+
74
+ stringify_dialect = "postgresql"
75
+ inherit_cache = True
76
+
77
+ @util.memoized_property
78
+ def excluded(
79
+ self,
80
+ ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
81
+ """Provide the ``excluded`` namespace for an ON CONFLICT statement
82
+
83
+ PG's ON CONFLICT clause allows reference to the row that would
84
+ be inserted, known as ``excluded``. This attribute provides
85
+ all columns in this row to be referenceable.
86
+
87
+ .. tip:: The :attr:`_postgresql.Insert.excluded` attribute is an
88
+ instance of :class:`_expression.ColumnCollection`, which provides
89
+ an interface the same as that of the :attr:`_schema.Table.c`
90
+ collection described at :ref:`metadata_tables_and_columns`.
91
+ With this collection, ordinary names are accessible like attributes
92
+ (e.g. ``stmt.excluded.some_column``), but special names and
93
+ dictionary method names should be accessed using indexed access,
94
+ such as ``stmt.excluded["column name"]`` or
95
+ ``stmt.excluded["values"]``. See the docstring for
96
+ :class:`_expression.ColumnCollection` for further examples.
97
+
98
+ .. seealso::
99
+
100
+ :ref:`postgresql_insert_on_conflict` - example of how
101
+ to use :attr:`_expression.Insert.excluded`
102
+
103
+ """
104
+ return alias(self.table, name="excluded").columns
105
+
106
+ _on_conflict_exclusive = _exclusive_against(
107
+ "_post_values_clause",
108
+ msgs={
109
+ "_post_values_clause": "This Insert construct already has "
110
+ "an ON CONFLICT clause established"
111
+ },
112
+ )
113
+
114
+ @_on_conflict_exclusive
115
+ def on_conflict_do_update(
116
+ self,
117
+ constraint: _OnConflictConstraintT = None,
118
+ index_elements: _OnConflictIndexElementsT = None,
119
+ index_where: _OnConflictIndexWhereT = None,
120
+ set_: _OnConflictSetT = None,
121
+ where: _OnConflictWhereT = None,
122
+ ) -> Self:
123
+ r"""
124
+ Specifies a DO UPDATE SET action for ON CONFLICT clause.
125
+
126
+ Either the ``constraint`` or ``index_elements`` argument is
127
+ required, but only one of these can be specified.
128
+
129
+ :param constraint:
130
+ The name of a unique or exclusion constraint on the table,
131
+ or the constraint object itself if it has a .name attribute.
132
+
133
+ :param index_elements:
134
+ A sequence consisting of string column names, :class:`_schema.Column`
135
+ objects, or other column expression objects that will be used
136
+ to infer a target index.
137
+
138
+ :param index_where:
139
+ Additional WHERE criterion that can be used to infer a
140
+ conditional target index.
141
+
142
+ :param set\_:
143
+ A dictionary or other mapping object
144
+ where the keys are either names of columns in the target table,
145
+ or :class:`_schema.Column` objects or other ORM-mapped columns
146
+ matching that of the target table, and expressions or literals
147
+ as values, specifying the ``SET`` actions to take.
148
+
149
+ .. versionadded:: 1.4 The
150
+ :paramref:`_postgresql.Insert.on_conflict_do_update.set_`
151
+ parameter supports :class:`_schema.Column` objects from the target
152
+ :class:`_schema.Table` as keys.
153
+
154
+ .. warning:: This dictionary does **not** take into account
155
+ Python-specified default UPDATE values or generation functions,
156
+ e.g. those specified using :paramref:`_schema.Column.onupdate`.
157
+ These values will not be exercised for an ON CONFLICT style of
158
+ UPDATE, unless they are manually specified in the
159
+ :paramref:`.Insert.on_conflict_do_update.set_` dictionary.
160
+
161
+ :param where:
162
+ Optional argument. An expression object representing a ``WHERE``
163
+ clause that restricts the rows affected by ``DO UPDATE SET``. Rows not
164
+ meeting the ``WHERE`` condition will not be updated (effectively a
165
+ ``DO NOTHING`` for those rows).
166
+
167
+
168
+ .. seealso::
169
+
170
+ :ref:`postgresql_insert_on_conflict`
171
+
172
+ """
173
+ return self.ext(
174
+ OnConflictDoUpdate(
175
+ constraint, index_elements, index_where, set_, where
176
+ )
177
+ )
178
+
179
+ @_on_conflict_exclusive
180
+ def on_conflict_do_nothing(
181
+ self,
182
+ constraint: _OnConflictConstraintT = None,
183
+ index_elements: _OnConflictIndexElementsT = None,
184
+ index_where: _OnConflictIndexWhereT = None,
185
+ ) -> Self:
186
+ """
187
+ Specifies a DO NOTHING action for ON CONFLICT clause.
188
+
189
+ The ``constraint`` and ``index_elements`` arguments
190
+ are optional, but only one of these can be specified.
191
+
192
+ :param constraint:
193
+ The name of a unique or exclusion constraint on the table,
194
+ or the constraint object itself if it has a .name attribute.
195
+
196
+ :param index_elements:
197
+ A sequence consisting of string column names, :class:`_schema.Column`
198
+ objects, or other column expression objects that will be used
199
+ to infer a target index.
200
+
201
+ :param index_where:
202
+ Additional WHERE criterion that can be used to infer a
203
+ conditional target index.
204
+
205
+ .. seealso::
206
+
207
+ :ref:`postgresql_insert_on_conflict`
208
+
209
+ """
210
+ return self.ext(
211
+ OnConflictDoNothing(constraint, index_elements, index_where)
212
+ )
213
+
214
+
215
+ class OnConflictClause(SyntaxExtension, ClauseElement):
216
+ stringify_dialect = "postgresql"
217
+
218
+ constraint_target: Optional[str]
219
+ inferred_target_elements: Optional[List[Union[str, schema.Column[Any]]]]
220
+ inferred_target_whereclause: Optional[
221
+ Union[ColumnElement[Any], TextClause]
222
+ ]
223
+
224
+ _traverse_internals = [
225
+ ("constraint_target", InternalTraversal.dp_string),
226
+ ("inferred_target_elements", InternalTraversal.dp_multi_list),
227
+ ("inferred_target_whereclause", InternalTraversal.dp_clauseelement),
228
+ ]
229
+
230
+ def __init__(
231
+ self,
232
+ constraint: _OnConflictConstraintT = None,
233
+ index_elements: _OnConflictIndexElementsT = None,
234
+ index_where: _OnConflictIndexWhereT = None,
235
+ ):
236
+ if constraint is not None:
237
+ if not isinstance(constraint, str) and isinstance(
238
+ constraint,
239
+ (schema.Constraint, ext.ExcludeConstraint),
240
+ ):
241
+ constraint = getattr(constraint, "name") or constraint
242
+
243
+ if constraint is not None:
244
+ if index_elements is not None:
245
+ raise ValueError(
246
+ "'constraint' and 'index_elements' are mutually exclusive"
247
+ )
248
+
249
+ if isinstance(constraint, str):
250
+ self.constraint_target = constraint
251
+ self.inferred_target_elements = None
252
+ self.inferred_target_whereclause = None
253
+ elif isinstance(constraint, schema.Index):
254
+ index_elements = constraint.expressions
255
+ index_where = constraint.dialect_options["postgresql"].get(
256
+ "where"
257
+ )
258
+ elif isinstance(constraint, ext.ExcludeConstraint):
259
+ index_elements = constraint.columns
260
+ index_where = constraint.where
261
+ else:
262
+ index_elements = constraint.columns
263
+ index_where = constraint.dialect_options["postgresql"].get(
264
+ "where"
265
+ )
266
+
267
+ if index_elements is not None:
268
+ self.constraint_target = None
269
+ self.inferred_target_elements = [
270
+ coercions.expect(roles.DDLConstraintColumnRole, column)
271
+ for column in index_elements
272
+ ]
273
+
274
+ self.inferred_target_whereclause = (
275
+ coercions.expect(
276
+ (
277
+ roles.StatementOptionRole
278
+ if isinstance(constraint, ext.ExcludeConstraint)
279
+ else roles.WhereHavingRole
280
+ ),
281
+ index_where,
282
+ )
283
+ if index_where is not None
284
+ else None
285
+ )
286
+
287
+ elif constraint is None:
288
+ self.constraint_target = self.inferred_target_elements = (
289
+ self.inferred_target_whereclause
290
+ ) = None
291
+
292
+ def apply_to_insert(self, insert_stmt: StandardInsert) -> None:
293
+ insert_stmt.apply_syntax_extension_point(
294
+ self.append_replacing_same_type, "post_values"
295
+ )
296
+
297
+
298
+ class OnConflictDoNothing(OnConflictClause):
299
+ __visit_name__ = "on_conflict_do_nothing"
300
+
301
+ inherit_cache = True
302
+
303
+
304
+ class OnConflictDoUpdate(OnConflictClause):
305
+ __visit_name__ = "on_conflict_do_update"
306
+
307
+ update_values_to_set: Dict[_DMLColumnElement, ColumnElement[Any]]
308
+ update_whereclause: Optional[ColumnElement[Any]]
309
+
310
+ _traverse_internals = OnConflictClause._traverse_internals + [
311
+ ("update_values_to_set", InternalTraversal.dp_dml_values),
312
+ ("update_whereclause", InternalTraversal.dp_clauseelement),
313
+ ]
314
+
315
+ def __init__(
316
+ self,
317
+ constraint: _OnConflictConstraintT = None,
318
+ index_elements: _OnConflictIndexElementsT = None,
319
+ index_where: _OnConflictIndexWhereT = None,
320
+ set_: _OnConflictSetT = None,
321
+ where: _OnConflictWhereT = None,
322
+ ):
323
+ super().__init__(
324
+ constraint=constraint,
325
+ index_elements=index_elements,
326
+ index_where=index_where,
327
+ )
328
+
329
+ if (
330
+ self.inferred_target_elements is None
331
+ and self.constraint_target is None
332
+ ):
333
+ raise ValueError(
334
+ "Either constraint or index_elements, "
335
+ "but not both, must be specified unless DO NOTHING"
336
+ )
337
+
338
+ if isinstance(set_, dict):
339
+ if not set_:
340
+ raise ValueError("set parameter dictionary must not be empty")
341
+ elif isinstance(set_, ColumnCollection):
342
+ set_ = dict(set_)
343
+ else:
344
+ raise ValueError(
345
+ "set parameter must be a non-empty dictionary "
346
+ "or a ColumnCollection such as the `.c.` collection "
347
+ "of a Table object"
348
+ )
349
+
350
+ self.update_values_to_set = {
351
+ coercions.expect(roles.DMLColumnRole, k): coercions.expect(
352
+ roles.ExpressionElementRole, v, type_=NULLTYPE, is_crud=True
353
+ )
354
+ for k, v in set_.items()
355
+ }
356
+ self.update_whereclause = (
357
+ coercions.expect(roles.WhereHavingRole, where)
358
+ if where is not None
359
+ else None
360
+ )