5
5
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
6
6
7
7
8
+ import builtins
9
+ import sys
10
+ import typing
11
+ import typing_extensions
12
+
13
+
8
14
__all__ = (
9
15
'BitString' , 'Point' , 'Path' , 'Polygon' ,
10
16
'Box' , 'Line' , 'LineSegment' , 'Circle' ,
11
17
)
12
18
19
+ _BS = typing .TypeVar ('_BS' , bound = 'BitString' )
20
+ _P = typing .TypeVar ('_P' , bound = 'Point' )
21
+ _BitOrder = typing_extensions .Literal ['big' , 'little' ]
22
+
13
23
14
24
class BitString :
15
25
"""Immutable representation of PostgreSQL `bit` and `varbit` types."""
16
26
17
27
__slots__ = '_bytes' , '_bitlength'
18
28
19
- def __init__ (self , bitstring = None ):
29
+ def __init__ (self ,
30
+ bitstring : typing .Optional [builtins .bytes ] = None ) -> None :
20
31
if not bitstring :
21
32
self ._bytes = bytes ()
22
33
self ._bitlength = 0
@@ -28,7 +39,7 @@ def __init__(self, bitstring=None):
28
39
bit_pos = 0
29
40
30
41
for i , bit in enumerate (bitstring ):
31
- if bit == ' ' :
42
+ if bit == ' ' : # type: ignore
32
43
continue
33
44
bit = int (bit )
34
45
if bit != 0 and bit != 1 :
@@ -53,14 +64,15 @@ def __init__(self, bitstring=None):
53
64
self ._bitlength = bitlen
54
65
55
66
@classmethod
56
- def frombytes (cls , bytes_ = None , bitlength = None ):
57
- if bitlength is None and bytes_ is None :
58
- bytes_ = bytes ()
59
- bitlength = 0
60
-
61
- elif bitlength is None :
62
- bitlength = len (bytes_ ) * 8
63
-
67
+ def frombytes (cls : typing .Type [_BS ],
68
+ bytes_ : typing .Optional [builtins .bytes ] = None ,
69
+ bitlength : typing .Optional [int ] = None ) -> _BS :
70
+ if bitlength is None :
71
+ if bytes_ is None :
72
+ bytes_ = bytes ()
73
+ bitlength = 0
74
+ else :
75
+ bitlength = len (bytes_ ) * 8
64
76
else :
65
77
if bytes_ is None :
66
78
bytes_ = bytes (bitlength // 8 + 1 )
@@ -87,10 +99,10 @@ def frombytes(cls, bytes_=None, bitlength=None):
87
99
return result
88
100
89
101
@property
90
- def bytes (self ):
102
+ def bytes (self ) -> builtins . bytes :
91
103
return self ._bytes
92
104
93
- def as_string (self ):
105
+ def as_string (self ) -> str :
94
106
s = ''
95
107
96
108
for i in range (self ._bitlength ):
@@ -100,7 +112,8 @@ def as_string(self):
100
112
101
113
return s .strip ()
102
114
103
- def to_int (self , bitorder = 'big' , * , signed = False ):
115
+ def to_int (self , bitorder : _BitOrder = 'big' ,
116
+ * , signed : bool = False ) -> int :
104
117
"""Interpret the BitString as a Python int.
105
118
Acts similarly to int.from_bytes.
106
119
@@ -135,7 +148,8 @@ def to_int(self, bitorder='big', *, signed=False):
135
148
return x
136
149
137
150
@classmethod
138
- def from_int (cls , x , length , bitorder = 'big' , * , signed = False ):
151
+ def from_int (cls : typing .Type [_BS ], x : int , length : int ,
152
+ bitorder : _BitOrder = 'big' , * , signed : bool = False ) -> _BS :
139
153
"""Represent the Python int x as a BitString.
140
154
Acts similarly to int.to_bytes.
141
155
@@ -187,27 +201,27 @@ def from_int(cls, x, length, bitorder='big', *, signed=False):
187
201
bytes_ = x .to_bytes ((length + 7 ) // 8 , byteorder = 'big' )
188
202
return cls .frombytes (bytes_ , length )
189
203
190
- def __repr__ (self ):
204
+ def __repr__ (self ) -> str :
191
205
return '<BitString {}>' .format (self .as_string ())
192
206
193
207
__str__ = __repr__
194
208
195
- def __eq__ (self , other ) :
209
+ def __eq__ (self , other : object ) -> bool :
196
210
if not isinstance (other , BitString ):
197
211
return NotImplemented
198
212
199
213
return (self ._bytes == other ._bytes and
200
214
self ._bitlength == other ._bitlength )
201
215
202
- def __hash__ (self ):
216
+ def __hash__ (self ) -> int :
203
217
return hash ((self ._bytes , self ._bitlength ))
204
218
205
- def _getitem (self , i ) :
219
+ def _getitem (self , i : int ) -> int :
206
220
byte = self ._bytes [i // 8 ]
207
221
shift = 8 - i % 8 - 1
208
222
return (byte >> shift ) & 0x1
209
223
210
- def __getitem__ (self , i ) :
224
+ def __getitem__ (self , i : int ) -> int :
211
225
if isinstance (i , slice ):
212
226
raise NotImplementedError ('BitString does not support slices' )
213
227
@@ -216,100 +230,134 @@ def __getitem__(self, i):
216
230
217
231
return self ._getitem (i )
218
232
219
- def __len__ (self ):
233
+ def __len__ (self ) -> int :
220
234
return self ._bitlength
221
235
222
236
223
- class Point (tuple ):
237
+ if typing .TYPE_CHECKING or sys .version_info >= (3 , 6 ):
238
+ _PointBase = typing .Tuple [float , float ]
239
+ _BoxBase = typing .Tuple ['Point' , 'Point' ]
240
+ _LineBase = typing .Tuple [float , float , float ]
241
+ _LineSegmentBase = typing .Tuple ['Point' , 'Point' ]
242
+ _CircleBase = typing .Tuple ['Point' , float ]
243
+ else :
244
+ # In Python 3.5, subclassing from typing.Tuple does not make the
245
+ # subclass act like a tuple in certain situations (like starred
246
+ # expressions)
247
+ _PointBase = tuple
248
+ _BoxBase = tuple
249
+ _LineBase = tuple
250
+ _LineSegmentBase = tuple
251
+ _CircleBase = tuple
252
+
253
+
254
+ class Point (_PointBase ):
224
255
"""Immutable representation of PostgreSQL `point` type."""
225
256
226
257
__slots__ = ()
227
258
228
- def __new__ (cls , x , y ):
229
- return super ().__new__ (cls , (float (x ), float (y )))
230
-
231
- def __repr__ (self ):
259
+ def __new__ (cls ,
260
+ x : typing .Union [typing .SupportsFloat ,
261
+ 'builtins._SupportsIndex' ,
262
+ typing .Text ,
263
+ builtins .bytes ,
264
+ builtins .bytearray ],
265
+ y : typing .Union [typing .SupportsFloat ,
266
+ 'builtins._SupportsIndex' ,
267
+ typing .Text ,
268
+ builtins .bytes ,
269
+ builtins .bytearray ]) -> 'Point' :
270
+ return super ().__new__ (cls ,
271
+ typing .cast (typing .Any , (float (x ), float (y ))))
272
+
273
+ def __repr__ (self ) -> str :
232
274
return '{}.{}({})' .format (
233
275
type (self ).__module__ ,
234
276
type (self ).__name__ ,
235
277
tuple .__repr__ (self )
236
278
)
237
279
238
280
@property
239
- def x (self ):
281
+ def x (self ) -> float :
240
282
return self [0 ]
241
283
242
284
@property
243
- def y (self ):
285
+ def y (self ) -> float :
244
286
return self [1 ]
245
287
246
288
247
- class Box (tuple ):
289
+ class Box (_BoxBase ):
248
290
"""Immutable representation of PostgreSQL `box` type."""
249
291
250
292
__slots__ = ()
251
293
252
- def __new__ (cls , high , low ):
253
- return super ().__new__ (cls , (Point (* high ), Point (* low )))
294
+ def __new__ (cls , high : typing .Sequence [float ],
295
+ low : typing .Sequence [float ]) -> 'Box' :
296
+ return super ().__new__ (cls ,
297
+ typing .cast (typing .Any , (Point (* high ),
298
+ Point (* low ))))
254
299
255
- def __repr__ (self ):
300
+ def __repr__ (self ) -> str :
256
301
return '{}.{}({})' .format (
257
302
type (self ).__module__ ,
258
303
type (self ).__name__ ,
259
304
tuple .__repr__ (self )
260
305
)
261
306
262
307
@property
263
- def high (self ):
308
+ def high (self ) -> Point :
264
309
return self [0 ]
265
310
266
311
@property
267
- def low (self ):
312
+ def low (self ) -> Point :
268
313
return self [1 ]
269
314
270
315
271
- class Line (tuple ):
316
+ class Line (_LineBase ):
272
317
"""Immutable representation of PostgreSQL `line` type."""
273
318
274
319
__slots__ = ()
275
320
276
- def __new__ (cls , A , B , C ) :
277
- return super ().__new__ (cls , ( A , B , C ))
321
+ def __new__ (cls , A : float , B : float , C : float ) -> 'Line' :
322
+ return super ().__new__ (cls , typing . cast ( typing . Any , ( A , B , C ) ))
278
323
279
324
@property
280
- def A (self ):
325
+ def A (self ) -> float :
281
326
return self [0 ]
282
327
283
328
@property
284
- def B (self ):
329
+ def B (self ) -> float :
285
330
return self [1 ]
286
331
287
332
@property
288
- def C (self ):
333
+ def C (self ) -> float :
289
334
return self [2 ]
290
335
291
336
292
- class LineSegment (tuple ):
337
+ class LineSegment (_LineSegmentBase ):
293
338
"""Immutable representation of PostgreSQL `lseg` type."""
294
339
295
340
__slots__ = ()
296
341
297
- def __new__ (cls , p1 , p2 ):
298
- return super ().__new__ (cls , (Point (* p1 ), Point (* p2 )))
342
+ def __new__ (cls , p1 : typing .Sequence [float ],
343
+ p2 : typing .Sequence [float ]) -> 'LineSegment' :
344
+ return super ().__new__ (cls ,
345
+ typing .cast (typing .Any , (Point (* p1 ),
346
+ Point (* p2 ))))
299
347
300
- def __repr__ (self ):
348
+ def __repr__ (self ) -> str :
301
349
return '{}.{}({})' .format (
302
350
type (self ).__module__ ,
303
351
type (self ).__name__ ,
304
352
tuple .__repr__ (self )
305
353
)
306
354
307
355
@property
308
- def p1 (self ):
356
+ def p1 (self ) -> Point :
309
357
return self [0 ]
310
358
311
359
@property
312
- def p2 (self ):
360
+ def p2 (self ) -> Point :
313
361
return self [1 ]
314
362
315
363
@@ -318,34 +366,44 @@ class Path:
318
366
319
367
__slots__ = '_is_closed' , 'points'
320
368
321
- def __init__ (self , * points , is_closed = False ):
369
+ def __init__ (self , * points : typing .Sequence [float ],
370
+ is_closed : bool = False ) -> None :
322
371
self .points = tuple (Point (* p ) for p in points )
323
372
self ._is_closed = is_closed
324
373
325
374
@property
326
- def is_closed (self ):
375
+ def is_closed (self ) -> bool :
327
376
return self ._is_closed
328
377
329
- def __eq__ (self , other ) :
378
+ def __eq__ (self , other : object ) -> bool :
330
379
if not isinstance (other , Path ):
331
380
return NotImplemented
332
381
333
382
return (self .points == other .points and
334
383
self ._is_closed == other ._is_closed )
335
384
336
- def __hash__ (self ):
385
+ def __hash__ (self ) -> int :
337
386
return hash ((self .points , self .is_closed ))
338
387
339
- def __iter__ (self ):
388
+ def __iter__ (self ) -> typing . Iterator [ Point ] :
340
389
return iter (self .points )
341
390
342
- def __len__ (self ):
391
+ def __len__ (self ) -> int :
343
392
return len (self .points )
344
393
345
- def __getitem__ (self , i ):
394
+ @typing .overload
395
+ def __getitem__ (self , i : int ) -> Point :
396
+ ...
397
+
398
+ @typing .overload
399
+ def __getitem__ (self , i : slice ) -> typing .Tuple [Point , ...]:
400
+ ...
401
+
402
+ def __getitem__ (self , i : typing .Union [int , slice ]) \
403
+ -> typing .Union [Point , typing .Tuple [Point , ...]]:
346
404
return self .points [i ]
347
405
348
- def __contains__ (self , point ) :
406
+ def __contains__ (self , point : object ) -> bool :
349
407
return point in self .points
350
408
351
409
@@ -354,23 +412,23 @@ class Polygon(Path):
354
412
355
413
__slots__ = ()
356
414
357
- def __init__ (self , * points ) :
415
+ def __init__ (self , * points : typing . Sequence [ float ]) -> None :
358
416
# polygon is always closed
359
417
super ().__init__ (* points , is_closed = True )
360
418
361
419
362
- class Circle (tuple ):
420
+ class Circle (_CircleBase ):
363
421
"""Immutable representation of PostgreSQL `circle` type."""
364
422
365
423
__slots__ = ()
366
424
367
- def __new__ (cls , center , radius ) :
368
- return super ().__new__ (cls , ( center , radius ))
425
+ def __new__ (cls , center : Point , radius : float ) -> 'Circle' :
426
+ return super ().__new__ (cls , typing . cast ( typing . Any , ( center , radius ) ))
369
427
370
428
@property
371
- def center (self ):
429
+ def center (self ) -> Point :
372
430
return self [0 ]
373
431
374
432
@property
375
- def radius (self ):
433
+ def radius (self ) -> float :
376
434
return self [1 ]
0 commit comments