2727except ImportError :
2828 urlfetch , urlfetch_errors = None , None
2929
30+ try :
31+ import urllib3
32+ except ImportError :
33+ urllib3 = None
34+
3035# datadog
3136from datadog .api .exceptions import ProxyError , ClientError , HTTPError , HttpTimeout
3237
@@ -178,6 +183,56 @@ def raise_on_status(cls, result):
178183 raise HTTPError (status_code )
179184
180185
186+ class Urllib3Client (HTTPClient ):
187+ """
188+ HTTP client based on 3rd party `urllib3` module.
189+ """
190+
191+ _pool = None
192+ _pool_lock = Lock ()
193+
194+ @classmethod
195+ def request (cls , method , url , headers , params , data , timeout , proxies , verify , max_retries ):
196+ """
197+ Wrapper around `urllib3.PoolManager.request` method. This method will raise
198+ exceptions for HTTP status codes that are not 2xx.
199+ """
200+ try :
201+ with cls ._pool_lock :
202+ if cls ._pool is None :
203+ cls ._pool = urllib3 .PoolManager (
204+ timeout = timeout ,
205+ retries = urllib3 .util .retry .Retry (total = max_retries , backoff_factor = 0.1 ),
206+ cert_reqs = "CERT_REQUIRED" if verify else "CERT_NONE" ,
207+ )
208+
209+ response = cls ._pool .request (
210+ method , url , body = data , fields = params , headers = headers , timeout = timeout , retries = max_retries ,
211+ )
212+ cls .raise_on_status (response )
213+
214+ except urllib3 .exceptions .ProxyError as e :
215+ raise _remove_context (ProxyError (method , url , e ))
216+ except urllib3 .exceptions .MaxRetryError as e :
217+ raise _remove_context (ClientError (method , url , e ))
218+ except urllib3 .exceptions .TimeoutError as e :
219+ raise _remove_context (HttpTimeout (method , url , e ))
220+ except urllib3 .exceptions .HTTPError as e :
221+ raise _remove_context (HTTPError (e ))
222+
223+ return response
224+
225+ @classmethod
226+ def raise_on_status (cls , response ):
227+ """
228+ Raise on HTTP status code errors.
229+ """
230+ status_code = response .status
231+ if status_code < 200 or status_code >= 300 :
232+ if status_code not in (400 , 401 , 403 , 404 , 409 , 429 ):
233+ raise HTTPError (status_code , response .reason )
234+
235+
181236def resolve_http_client ():
182237 """
183238 Resolve an appropriate HTTP client based the defined priority and user environment.
@@ -190,6 +245,10 @@ def resolve_http_client():
190245 log .debug (u"Use `urlfetch` based HTTP client." )
191246 return URLFetchClient
192247
248+ if urllib3 :
249+ log .debug (u"Use `urllib3` based HTTP client." )
250+ return Urllib3Client
251+
193252 raise ImportError (
194253 u"Datadog API client was unable to resolve a HTTP client. " u" Please install `requests` library."
195254 )
0 commit comments