11"""Defines the base result object - which specifies how DomainTools API endpoints will be interacted with"""
2- import collections
2+
33import json
44import re
55import time
66import logging
77from datetime import datetime
88
9- from domaintools .exceptions import (BadRequestException , InternalServerErrorException , NotAuthorizedException ,
10- NotFoundException , ServiceException , ServiceUnavailableException ,
11- IncompleteResponseException , RequestUriTooLongException )
9+ from domaintools .exceptions import (
10+ BadRequestException ,
11+ InternalServerErrorException ,
12+ NotAuthorizedException ,
13+ NotFoundException ,
14+ ServiceException ,
15+ ServiceUnavailableException ,
16+ IncompleteResponseException ,
17+ RequestUriTooLongException ,
18+ )
19+ from domaintools .utils import get_feeds_products_list
20+
1221from httpx import Client
1322
14- try : # pragma: no cover
23+ try : # pragma: no cover
1524 from collections .abc import MutableMapping , MutableSequence
16- except ImportError : # pragma: no cover
25+ except ImportError : # pragma: no cover
1726 from collections import MutableMapping , MutableSequence
1827
1928log = logging .getLogger (__name__ )
2029
30+
2131class Results (MutableMapping , MutableSequence ):
2232 """The base (abstract) DomainTools result definition"""
2333
24- def __init__ (self , api , product , url , items_path = (), response_path = ('response' , ), proxy_url = None , ** kwargs ):
34+ def __init__ (
35+ self ,
36+ api ,
37+ product ,
38+ url ,
39+ items_path = (),
40+ response_path = ("response" ,),
41+ proxy_url = None ,
42+ ** kwargs ,
43+ ):
2544 self .api = api
2645 self .product = product
2746 self .url = url
@@ -41,59 +60,79 @@ def _wait_time(self):
4160
4261 now = datetime .now ()
4362 limit = self .api .limits [self .product ]
44- if ' last_scheduled' not in limit :
45- limit [' last_scheduled' ] = now
63+ if " last_scheduled" not in limit :
64+ limit [" last_scheduled" ] = now
4665 return None
4766
48- safe_after = limit [' last_scheduled' ] + limit [' interval' ]
67+ safe_after = limit [" last_scheduled" ] + limit [" interval" ]
4968 wait_for = 0
5069 if now < safe_after :
5170 wait_for = safe_after - now
52- wait_for = float (wait_for .seconds ) + (float (wait_for .microseconds ) / 1000000.0 )
53- limit ['last_scheduled' ] = safe_after
71+ wait_for = float (wait_for .seconds ) + (
72+ float (wait_for .microseconds ) / 1000000.0
73+ )
74+ limit ["last_scheduled" ] = safe_after
5475 else :
55- limit [' last_scheduled' ] = now
76+ limit [" last_scheduled" ] = now
5677
5778 return wait_for
5879
5980 def _make_request (self ):
6081
61- with Client (verify = self .api .verify_ssl , proxies = self .api .proxy_url , timeout = None ) as session :
62- if self .product in ['iris-investigate' , 'iris-enrich' , 'iris-detect-escalate-domains' ]:
82+ with Client (
83+ verify = self .api .verify_ssl , proxies = self .api .proxy_url , timeout = None
84+ ) as session :
85+ if self .product in [
86+ "iris-investigate" ,
87+ "iris-enrich" ,
88+ "iris-detect-escalate-domains" ,
89+ ]:
6390 post_data = self .kwargs .copy ()
6491 post_data .update (self .api .extra_request_params )
6592 return session .post (url = self .url , data = post_data )
66- elif self .product in [' iris-detect-manage-watchlist-domains' ]:
93+ elif self .product in [" iris-detect-manage-watchlist-domains" ]:
6794 patch_data = self .kwargs .copy ()
6895 patch_data .update (self .api .extra_request_params )
6996 return session .patch (url = self .url , json = patch_data )
7097 else :
71- return session .get (url = self .url , params = self .kwargs , ** self .api .extra_request_params )
98+ return session .get (
99+ url = self .url , params = self .kwargs , ** self .api .extra_request_params
100+ )
72101
73102 def _get_results (self ):
74103 wait_for = self ._wait_time ()
75- if self .api .rate_limit and (wait_for is None or self .product == 'account-information' ):
104+ if self .api .rate_limit and (
105+ wait_for is None or self .product == "account-information"
106+ ):
76107 data = self ._make_request ()
77- if data .status_code == 503 : # pragma: no cover
108+ if data .status_code == 503 : # pragma: no cover
78109 sleeptime = 60
79- log .info ('503 encountered for [%s] - sleeping [%s] seconds before retrying request.' ,
80- self .product , sleeptime )
110+ log .info (
111+ "503 encountered for [%s] - sleeping [%s] seconds before retrying request." ,
112+ self .product ,
113+ sleeptime ,
114+ )
81115 time .sleep (sleeptime )
82116 self ._wait_time ()
83117 data = self ._make_request ()
84118 return data
85119
86120 if wait_for > 0 :
87- log .info ('Sleeping for [%s] prior to requesting [%s].' ,
88- wait_for , self .product )
121+ log .info (
122+ "Sleeping for [%s] prior to requesting [%s]." , wait_for , self .product
123+ )
89124 time .sleep (wait_for )
90125 return self ._make_request ()
91126
92127 def data (self ):
93128 if self ._data is None :
94129 results = self ._get_results ()
95130 self .setStatus (results .status_code , results )
96- if self .kwargs .get ('format' , 'json' ) == 'json' :
131+ if (
132+ self .kwargs .get ("format" , "json" ) == "json"
133+ and self .product
134+ not in get_feeds_products_list () # Special handling of feeds products' data to preserve the result in jsonline format
135+ ):
97136 self ._data = results .json ()
98137 else :
99138 self ._data = results .text
@@ -104,24 +143,28 @@ def data(self):
104143 self ._limit_exceeded_message = message
105144
106145 if self ._limit_exceeded is True :
107- raise ServiceException (503 , "Limit Exceeded{}" .format (self ._limit_exceeded_message ))
146+ raise ServiceException (
147+ 503 , "Limit Exceeded{}" .format (self ._limit_exceeded_message )
148+ )
108149 else :
109150 return self ._data
110151
111152 def check_limit_exceeded (self ):
112- if self .kwargs .get ('format' , 'json' ) == 'json' :
113- if ("response" in self ._data and
114- "limit_exceeded" in self ._data ['response' ] and
115- self ._data ['response' ]['limit_exceeded' ] is True ):
116- return True , self ._data ['response' ]['message' ]
153+ if self .kwargs .get ("format" , "json" ) == "json" :
154+ if (
155+ "response" in self ._data
156+ and "limit_exceeded" in self ._data ["response" ]
157+ and self ._data ["response" ]["limit_exceeded" ] is True
158+ ):
159+ return True , self ._data ["response" ]["message" ]
117160 # TODO: handle html, xml response errors better.
118161 elif "response" in self ._data and "limit_exceeded" in self ._data :
119162 return True , "limit exceeded"
120163 return False , ""
121164
122165 @property
123166 def status (self ):
124- if not getattr (self , ' _status' , None ):
167+ if not getattr (self , " _status" , None ):
125168 self ._status = self ._get_results ().status_code
126169
127170 return self ._status
@@ -135,7 +178,7 @@ def setStatus(self, code, response=None):
135178 if response is not None :
136179 try :
137180 reason = response .json ()
138- except Exception : # pragma: no cover
181+ except Exception : # pragma: no cover
139182 reason = response .text
140183 if callable (reason ):
141184 reason = reason ()
@@ -146,16 +189,16 @@ def setStatus(self, code, response=None):
146189 raise NotAuthorizedException (code , reason )
147190 elif code == 404 :
148191 raise NotFoundException (code , reason )
149- elif code == 500 : # pragma: no cover
192+ elif code == 500 : # pragma: no cover
150193 raise InternalServerErrorException (code , reason )
151- elif code == 503 : # pragma: no cover
194+ elif code == 503 : # pragma: no cover
152195 raise ServiceUnavailableException (code , reason )
153- elif code == 206 : # pragma: no cover
196+ elif code == 206 : # pragma: no cover
154197 raise IncompleteResponseException (code , reason )
155- elif code == 414 : # pragma: no cover
198+ elif code == 414 : # pragma: no cover
156199 raise RequestUriTooLongException (code , reason )
157- else : # pragma: no cover
158- raise ServiceException (code , ' Unknown Exception' )
200+ else : # pragma: no cover
201+ raise ServiceException (code , " Unknown Exception" )
159202
160203 def response (self ):
161204 if self ._response is None :
@@ -171,7 +214,7 @@ def items(self):
171214
172215 def emails (self ):
173216 """Find and returns all emails mentioned in the response"""
174- return set (re .findall (r' [\w\.-]+@[\w\.-]+' , str (self .response ())))
217+ return set (re .findall (r" [\w\.-]+@[\w\.-]+" , str (self .response ())))
175218
176219 def _items (self ):
177220 if self ._items_list is None :
@@ -221,25 +264,54 @@ def __exit__(self, *args):
221264
222265 @property
223266 def json (self ):
224- self .kwargs .pop ('format' , None )
225- return self .__class__ (format = 'json' , product = self .product , url = self .url , items_path = self .items_path ,
226- response_path = self .response_path , api = self .api , ** self .kwargs )
267+ self .kwargs .pop ("format" , None )
268+ return self .__class__ (
269+ format = "json" ,
270+ product = self .product ,
271+ url = self .url ,
272+ items_path = self .items_path ,
273+ response_path = self .response_path ,
274+ api = self .api ,
275+ ** self .kwargs ,
276+ )
227277
228278 @property
229279 def xml (self ):
230- self .kwargs .pop ('format' , None )
231- return self .__class__ (format = 'xml' , product = self .product , url = self .url , items_path = self .items_path ,
232- response_path = self .response_path , api = self .api , ** self .kwargs )
280+ self .kwargs .pop ("format" , None )
281+ return self .__class__ (
282+ format = "xml" ,
283+ product = self .product ,
284+ url = self .url ,
285+ items_path = self .items_path ,
286+ response_path = self .response_path ,
287+ api = self .api ,
288+ ** self .kwargs ,
289+ )
233290
234291 @property
235292 def html (self ):
236- self .kwargs .pop ('format' , None )
237- return self .__class__ (api = self .api , product = self .product , url = self .url , items_path = self .items_path ,
238- response_path = self .response_path , format = 'html' , ** self .kwargs )
293+ self .kwargs .pop ("format" , None )
294+ return self .__class__ (
295+ api = self .api ,
296+ product = self .product ,
297+ url = self .url ,
298+ items_path = self .items_path ,
299+ response_path = self .response_path ,
300+ format = "html" ,
301+ ** self .kwargs ,
302+ )
239303
240304 def as_list (self ):
241- return '\n ' .join ([json .dumps (item , indent = 4 , separators = (',' , ': ' )) for item in self ._items ()])
305+ return "\n " .join (
306+ [
307+ json .dumps (item , indent = 4 , separators = ("," , ": " ))
308+ for item in self ._items ()
309+ ]
310+ )
242311
243312 def __str__ (self ):
244- return str (json .dumps (self .data (), indent = 4 ,
245- separators = (',' , ': ' )) if self .kwargs .get ('format' , 'json' ) == 'json' else self .data ())
313+ return str (
314+ json .dumps (self .data (), indent = 4 , separators = ("," , ": " ))
315+ if self .kwargs .get ("format" , "json" ) == "json"
316+ else self .data ()
317+ )
0 commit comments