37
37
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Requests.git"
38
38
39
39
import errno
40
+ import sys
41
+
42
+ if sys .implementation .name == "circuitpython" :
43
+
44
+ def cast (_t , value ):
45
+ """No-op shim for the typing.cast() function which is not available in CircuitPython."""
46
+ return value
47
+
48
+
49
+ else :
50
+ from ssl import SSLContext
51
+ from types import ModuleType , TracebackType
52
+ from typing import Any , Dict , List , Optional , Tuple , Type , Union , cast
53
+ from typing_extensions import Protocol
54
+
55
+ # Based on https://github.com/python/typeshed/blob/master/stdlib/_socket.pyi
56
+ class CommonSocketType (Protocol ):
57
+ """Describes the common structure every socket type must have."""
58
+
59
+ def send (self , data : bytes , flags : int = ...) -> None :
60
+ """Send data to the socket. The meaning of the optional flags kwarg is
61
+ implementation-specific."""
62
+ ...
63
+
64
+ def settimeout (self , value : Optional [float ]) -> None :
65
+ """Set a timeout on blocking socket operations."""
66
+ ...
67
+
68
+ def close (self ) -> None :
69
+ """Close the socket."""
70
+ ...
71
+
72
+ class CommonCircuitPythonSocketType (CommonSocketType , Protocol ):
73
+ """Describes the common structure every CircuitPython socket type must have."""
74
+
75
+ def connect (
76
+ self ,
77
+ address : Tuple [str , int ],
78
+ conntype : Optional [int ] = ...,
79
+ ) -> None :
80
+ """Connect to a remote socket at the provided (host, port) address. The conntype
81
+ kwarg optionally may indicate SSL or not, depending on the underlying interface."""
82
+ ...
83
+
84
+ class LegacyCircuitPythonSocketType (CommonCircuitPythonSocketType , Protocol ):
85
+ """Describes the structure a legacy CircuitPython socket type must have."""
86
+
87
+ def recv (self , bufsize : int = ...) -> bytes :
88
+ """Receive data from the socket. The return value is a bytes object representing
89
+ the data received. The maximum amount of data to be received at once is specified
90
+ by bufsize."""
91
+ ...
92
+
93
+ class SupportsRecvWithFlags (Protocol ):
94
+ """Describes a type that posseses a socket recv() method supporting the flags kwarg."""
95
+
96
+ def recv (self , bufsize : int = ..., flags : int = ...) -> bytes :
97
+ """Receive data from the socket. The return value is a bytes object representing
98
+ the data received. The maximum amount of data to be received at once is specified
99
+ by bufsize. The meaning of the optional flags kwarg is implementation-specific."""
100
+ ...
101
+
102
+ class SupportsRecvInto (Protocol ):
103
+ """Describes a type that possesses a socket recv_into() method."""
104
+
105
+ def recv_into (
106
+ self , buffer : bytearray , nbytes : int = ..., flags : int = ...
107
+ ) -> int :
108
+ """Receive up to nbytes bytes from the socket, storing the data into the provided
109
+ buffer. If nbytes is not specified (or 0), receive up to the size available in the
110
+ given buffer. The meaning of the optional flags kwarg is implementation-specific.
111
+ Returns the number of bytes received."""
112
+ ...
113
+
114
+ class CircuitPythonSocketType (
115
+ CommonCircuitPythonSocketType ,
116
+ SupportsRecvInto ,
117
+ SupportsRecvWithFlags ,
118
+ Protocol ,
119
+ ): # pylint: disable=too-many-ancestors
120
+ """Describes the structure every modern CircuitPython socket type must have."""
121
+
122
+ ...
123
+
124
+ class StandardPythonSocketType (
125
+ CommonSocketType , SupportsRecvInto , SupportsRecvWithFlags , Protocol
126
+ ):
127
+ """Describes the structure every standard Python socket type must have."""
40
128
41
- try :
42
- from typing import Union , TypeVar , Optional , Dict , Any , List , Type
43
- import types
44
- from types import TracebackType
45
- import ssl
46
- import adafruit_esp32spi .adafruit_esp32spi_socket as esp32_socket
47
- import adafruit_wiznet5k .adafruit_wiznet5k_socket as wiznet_socket
48
- import adafruit_fona .adafruit_fona_socket as cellular_socket
49
- from adafruit_esp32spi .adafruit_esp32spi import ESP_SPIcontrol
50
- from adafruit_wiznet5k .adafruit_wiznet5k import WIZNET5K
51
- from adafruit_fona .adafruit_fona import FONA
52
- import socket as cpython_socket
53
-
54
- SocketType = TypeVar (
55
- "SocketType" ,
56
- esp32_socket .socket ,
57
- wiznet_socket .socket ,
58
- cellular_socket .socket ,
59
- cpython_socket .socket ,
60
- )
61
- SocketpoolModuleType = types .ModuleType
62
- SSLContextType = (
63
- ssl .SSLContext
64
- ) # Can use either CircuitPython or CPython ssl module
65
- InterfaceType = TypeVar ("InterfaceType" , ESP_SPIcontrol , WIZNET5K , FONA )
129
+ def connect (self , address : Union [Tuple [Any , ...], str , bytes ]) -> None :
130
+ """Connect to a remote socket at the provided address."""
131
+ ...
132
+
133
+ SocketType = Union [
134
+ LegacyCircuitPythonSocketType ,
135
+ CircuitPythonSocketType ,
136
+ StandardPythonSocketType ,
137
+ ]
138
+
139
+ SocketpoolModuleType = ModuleType
140
+
141
+ class InterfaceType (Protocol ):
142
+ """Describes the structure every interface type must have."""
143
+
144
+ @property
145
+ def TLS_MODE (self ) -> int : # pylint: disable=invalid-name
146
+ """Constant representing that a socket's connection mode is TLS."""
147
+ ...
148
+
149
+ SSLContextType = Union [SSLContext , "_FakeSSLContext" ]
66
150
67
- except ImportError :
68
- pass
69
151
70
152
# CircuitPython 6.0 does not have the bytearray.split method.
71
153
# This function emulates buf.split(needle)[0], which is the functionality
@@ -157,7 +239,7 @@ def _recv_into(self, buf: bytearray, size: int = 0) -> int:
157
239
read_size = len (b )
158
240
buf [:read_size ] = b
159
241
return read_size
160
- return self .socket .recv_into (buf , size )
242
+ return cast ( "SupportsRecvInto" , self .socket ) .recv_into (buf , size )
161
243
162
244
@staticmethod
163
245
def _find (buf : bytes , needle : bytes , start : int , end : int ) -> int :
@@ -440,7 +522,7 @@ def _free_sockets(self) -> None:
440
522
441
523
def _get_socket (
442
524
self , host : str , port : int , proto : str , * , timeout : float = 1
443
- ) -> SocketType :
525
+ ) -> CircuitPythonSocketType :
444
526
# pylint: disable=too-many-branches
445
527
key = (host , port , proto )
446
528
if key in self ._open_sockets :
@@ -693,15 +775,15 @@ def delete(self, url: str, **kw) -> Response:
693
775
694
776
695
777
class _FakeSSLSocket :
696
- def __init__ (self , socket : SocketType , tls_mode : int ) -> None :
778
+ def __init__ (self , socket : CircuitPythonSocketType , tls_mode : int ) -> None :
697
779
self ._socket = socket
698
780
self ._mode = tls_mode
699
781
self .settimeout = socket .settimeout
700
782
self .send = socket .send
701
783
self .recv = socket .recv
702
784
self .close = socket .close
703
785
704
- def connect (self , address : Union [ bytes , str ]) -> None :
786
+ def connect (self , address : Tuple [ str , int ]) -> None :
705
787
"""connect wrapper to add non-standard mode parameter"""
706
788
try :
707
789
return self ._socket .connect (address , self ._mode )
@@ -714,7 +796,7 @@ def __init__(self, iface: InterfaceType) -> None:
714
796
self ._iface = iface
715
797
716
798
def wrap_socket (
717
- self , socket : SocketType , server_hostname : Optional [str ] = None
799
+ self , socket : CircuitPythonSocketType , server_hostname : Optional [str ] = None
718
800
) -> _FakeSSLSocket :
719
801
"""Return the same socket"""
720
802
# pylint: disable=unused-argument
0 commit comments