5757import mimetypes
5858import os
5959import re
60+ import threading
6061import time
6162import urllib
6263import urllib .parse
63- from collections import defaultdict
64+ from collections import deque
6465from datetime import datetime , timezone
6566from io import IOBase
66- from typing import TYPE_CHECKING , Any , Callable , Dict , Generic , ItemsView , List , Optional , Tuple , Type , TypeVar , Union
67+ from typing import (
68+ TYPE_CHECKING ,
69+ Any ,
70+ Callable ,
71+ Deque ,
72+ Dict ,
73+ Generic ,
74+ ItemsView ,
75+ List ,
76+ Optional ,
77+ Tuple ,
78+ Type ,
79+ TypeVar ,
80+ Union ,
81+ )
6782
6883import requests
6984import requests .adapters
@@ -166,7 +181,7 @@ def getresponse(self) -> RequestsResponse:
166181 return RequestsResponse (r )
167182
168183 def close (self ) -> None :
169- return
184+ self . session . close ()
170185
171186
172187class HTTPRequestsConnectionClass :
@@ -229,7 +244,7 @@ def getresponse(self) -> RequestsResponse:
229244 return RequestsResponse (r )
230245
231246 def close (self ) -> None :
232- return
247+ self . session . close ()
233248
234249
235250class Requester :
@@ -238,7 +253,6 @@ class Requester:
238253
239254 __httpConnectionClass = HTTPRequestsConnectionClass
240255 __httpsConnectionClass = HTTPSRequestsConnectionClass
241- __connection = None
242256 __persist = True
243257 __logger : Optional [logging .Logger ] = None
244258
@@ -337,7 +351,6 @@ def _initializeDebugFeature(self) -> None:
337351 __connectionClass : Union [Type [HTTPRequestsConnectionClass ], Type [HTTPSRequestsConnectionClass ]]
338352 __hostname : str
339353 __authorizationHeader : Optional [str ]
340- __last_requests : Dict [str , float ]
341354 __seconds_between_requests : Optional [float ]
342355 __seconds_between_writes : Optional [float ]
343356
@@ -369,14 +382,17 @@ def __init__(
369382 self .__pool_size = pool_size
370383 self .__seconds_between_requests = seconds_between_requests
371384 self .__seconds_between_writes = seconds_between_writes
372- self .__last_requests = defaultdict ( lambda : 0.0 )
385+ self .__last_requests : Dict [ str , float ] = dict ( )
373386 self .__scheme = o .scheme
374387 if o .scheme == "https" :
375388 self .__connectionClass = self .__httpsConnectionClass
376389 elif o .scheme == "http" :
377390 self .__connectionClass = self .__httpConnectionClass
378391 else :
379392 assert False , "Unknown URL scheme"
393+ self .__connection : Optional [Union [HTTPRequestsConnectionClass , HTTPSRequestsConnectionClass ]] = None
394+ self .__connection_lock = threading .Lock ()
395+ self .__custom_connections : Deque [Union [HTTPRequestsConnectionClass , HTTPSRequestsConnectionClass ]] = deque ()
380396 self .rate_limiting = (- 1 , - 1 )
381397 self .rate_limiting_resettime = 0
382398 self .FIX_REPO_GET_GIT_REF = True
@@ -397,6 +413,33 @@ def __init__(
397413 if isinstance (self .__auth , WithRequester ):
398414 self .__auth .withRequester (self )
399415
416+ def __getstate__ (self ) -> Dict [str , Any ]:
417+ state = self .__dict__ .copy ()
418+ # __connection_lock is not picklable
419+ del state ["_Requester__connection_lock" ]
420+ # __connection is not usable on remote, so ignore it
421+ del state ["_Requester__connection" ]
422+ # __custom_connections is not usable on remote, so ignore it
423+ del state ["_Requester__custom_connections" ]
424+ return state
425+
426+ def __setstate__ (self , state : Dict [str , Any ]) -> None :
427+ self .__dict__ .update (state )
428+ self .__connection_lock = threading .Lock ()
429+ self .__connection = None
430+ self .__custom_connections = deque ()
431+
432+ def close (self ) -> None :
433+ """
434+ Close the connection to the server.
435+ """
436+ with self .__connection_lock :
437+ if self .__connection is not None :
438+ self .__connection .close ()
439+ self .__connection = None
440+ while self .__custom_connections :
441+ self .__custom_connections .popleft ().close ()
442+
400443 @property
401444 def kwargs (self ) -> Dict [str , Any ]:
402445 """
@@ -499,13 +542,15 @@ def __customConnection(
499542 retry = self .__retry ,
500543 pool_size = self .__pool_size ,
501544 )
545+ self .__custom_connections .append (cnx )
502546 elif o .scheme == "https" :
503547 cnx = self .__httpsConnectionClass (
504548 o .hostname , # type: ignore
505549 o .port ,
506550 retry = self .__retry ,
507551 pool_size = self .__pool_size ,
508552 )
553+ self .__custom_connections .append (cnx )
509554 return cnx
510555
511556 @classmethod
@@ -717,7 +762,6 @@ def __requestRaw(
717762 responseHeaders = {k .lower (): v for k , v in response .getheaders ()}
718763 output = response .read ()
719764
720- cnx .close ()
721765 if input :
722766 if isinstance (input , IOBase ):
723767 input .close ()
@@ -822,14 +866,19 @@ def __createConnection(
822866 if self .__persist and self .__connection is not None :
823867 return self .__connection
824868
825- self .__connection = self .__connectionClass (
826- self .__hostname ,
827- self .__port ,
828- retry = self .__retry ,
829- pool_size = self .__pool_size ,
830- timeout = self .__timeout ,
831- verify = self .__verify ,
832- )
869+ with self .__connection_lock :
870+ if self .__connection is not None :
871+ if self .__persist :
872+ return self .__connection
873+ self .__connection .close ()
874+ self .__connection = self .__connectionClass (
875+ self .__hostname ,
876+ self .__port ,
877+ retry = self .__retry ,
878+ pool_size = self .__pool_size ,
879+ timeout = self .__timeout ,
880+ verify = self .__verify ,
881+ )
833882
834883 return self .__connection
835884
0 commit comments