12
12
# See the License for the specific language governing permissions and
13
13
# limitations under the License.
14
14
from types import TracebackType
15
- from typing import Any , Iterator , List , Mapping , Optional , Sequence , Tuple , Type , Union
15
+ from typing import (
16
+ Any ,
17
+ Callable ,
18
+ Iterator ,
19
+ List ,
20
+ Mapping ,
21
+ Optional ,
22
+ Sequence ,
23
+ Tuple ,
24
+ Type ,
25
+ Union ,
26
+ )
16
27
17
28
from typing_extensions import Protocol
18
29
@@ -112,23 +123,45 @@ class DBAPI2Module(Protocol):
112
123
# extends from this hierarchy. See
113
124
# https://docs.python.org/3/library/sqlite3.html?highlight=sqlite3#exceptions
114
125
# https://www.postgresql.org/docs/current/errcodes-appendix.html#ERRCODES-TABLE
115
- Warning : Type [Exception ]
116
- Error : Type [Exception ]
126
+ #
127
+ # Note: rather than
128
+ # x: T
129
+ # we write
130
+ # @property
131
+ # def x(self) -> T: ...
132
+ # which expresses that the protocol attribute `x` is read-only. The mypy docs
133
+ # https://mypy.readthedocs.io/en/latest/common_issues.html#covariant-subtyping-of-mutable-protocol-members-is-rejected
134
+ # explain why this is necessary for safety. TL;DR: we shouldn't be able to write
135
+ # to `x`, only read from it. See also https://github.com/python/mypy/issues/6002 .
136
+ @property
137
+ def Warning (self ) -> Type [Exception ]:
138
+ ...
139
+
140
+ @property
141
+ def Error (self ) -> Type [Exception ]:
142
+ ...
117
143
118
144
# Errors are divided into `InterfaceError`s (something went wrong in the database
119
145
# driver) and `DatabaseError`s (something went wrong in the database). These are
120
146
# both subclasses of `Error`, but we can't currently express this in type
121
147
# annotations due to https://github.com/python/mypy/issues/8397
122
- InterfaceError : Type [Exception ]
123
- DatabaseError : Type [Exception ]
148
+ @property
149
+ def InterfaceError (self ) -> Type [Exception ]:
150
+ ...
151
+
152
+ @property
153
+ def DatabaseError (self ) -> Type [Exception ]:
154
+ ...
124
155
125
156
# Everything below is a subclass of `DatabaseError`.
126
157
127
158
# Roughly: the database rejected a nonsensical value. Examples:
128
159
# - An integer was too big for its data type.
129
160
# - An invalid date time was provided.
130
161
# - A string contained a null code point.
131
- DataError : Type [Exception ]
162
+ @property
163
+ def DataError (self ) -> Type [Exception ]:
164
+ ...
132
165
133
166
# Roughly: something went wrong in the database, but it's not within the application
134
167
# programmer's control. Examples:
@@ -138,28 +171,45 @@ class DBAPI2Module(Protocol):
138
171
# - A serialisation failure occurred.
139
172
# - The database ran out of resources, such as storage, memory, connections, etc.
140
173
# - The database encountered an error from the operating system.
141
- OperationalError : Type [Exception ]
174
+ @property
175
+ def OperationalError (self ) -> Type [Exception ]:
176
+ ...
142
177
143
178
# Roughly: we've given the database data which breaks a rule we asked it to enforce.
144
179
# Examples:
145
180
# - Stop, criminal scum! You violated the foreign key constraint
146
181
# - Also check constraints, non-null constraints, etc.
147
- IntegrityError : Type [Exception ]
182
+ @property
183
+ def IntegrityError (self ) -> Type [Exception ]:
184
+ ...
148
185
149
186
# Roughly: something went wrong within the database server itself.
150
- InternalError : Type [Exception ]
187
+ @property
188
+ def InternalError (self ) -> Type [Exception ]:
189
+ ...
151
190
152
191
# Roughly: the application did something silly that needs to be fixed. Examples:
153
192
# - We don't have permissions to do something.
154
193
# - We tried to create a table with duplicate column names.
155
194
# - We tried to use a reserved name.
156
195
# - We referred to a column that doesn't exist.
157
- ProgrammingError : Type [Exception ]
196
+ @property
197
+ def ProgrammingError (self ) -> Type [Exception ]:
198
+ ...
158
199
159
200
# Roughly: we've tried to do something that this database doesn't support.
160
- NotSupportedError : Type [Exception ]
201
+ @property
202
+ def NotSupportedError (self ) -> Type [Exception ]:
203
+ ...
161
204
162
- def connect (self , ** parameters : object ) -> Connection :
205
+ # We originally wrote
206
+ # def connect(self, *args, **kwargs) -> Connection: ...
207
+ # But mypy doesn't seem to like that because sqlite3.connect takes a mandatory
208
+ # positional argument. We can't make that part of the signature though, because
209
+ # psycopg2.connect doesn't have a mandatory positional argument. Instead, we use
210
+ # the following slightly unusual workaround.
211
+ @property
212
+ def connect (self ) -> Callable [..., Connection ]:
163
213
...
164
214
165
215
0 commit comments