33from newsdataapi import constants
44from typing import Optional ,Union
55from datetime import datetime ,timezone
6- from urllib .parse import urlencode , quote
76from newsdataapi .helpers import FileHandler
87from requests .exceptions import RequestException
8+ from urllib .parse import urlencode , quote ,urlparse ,parse_qs
99from newsdataapi .newsdataapi_exception import NewsdataException
1010
1111class NewsDataApiClient (FileHandler ):
@@ -42,29 +42,61 @@ def api_proxies( self, proxies:dict)->None:
4242 """ Configure Proxie dictionary """
4343 self .proxies = proxies
4444
45- def __validate_parms (self ,param : str , value : Union [ list , int , str , bool ] )-> dict :
45+ def __validate_parms (self ,user_param : dict )-> dict :
4646 bool_params = {'full_content' ,'image' ,'video' ,'removeduplicate' }
4747 int_params = {'size' }
4848 string_params = {
4949 'q' ,'qInTitle' ,'country' ,'category' ,'language' ,'domain' ,'domainurl' ,'excludedomain' ,'timezone' ,'page' ,
5050 'from_date' ,'to_date' ,'apikey' ,'qInMeta' ,'prioritydomain' ,'timeframe' ,'tag' ,'sentiment' ,'region' ,'coin' ,
5151 'excludefield'
5252 }
53+
54+ def validate_url (url :str )-> str :
55+ valid_fn_parms = {k .lower () for k in user_param .keys ()}
56+ parsed_url = urlparse (url )
57+ if parsed_url .netloc :
58+ q_string = parse_qs (parsed_url .query )
59+ else :
60+ q_string = parse_qs (url )
61+
62+ valid_q_string = {}
63+ for k ,v in q_string .items ():
64+ k = k .strip ().strip ('%' ).strip ('?' ).lower ()
65+ if k in valid_fn_parms :
66+ valid_q_string [k ] = v [0 ]
67+ else :
68+ raise TypeError (f'Provided parameter is invalid: { k } ' )
69+
70+ if not valid_q_string .get ('apikey' ):
71+ valid_q_string ['apikey' ] = self .apikey
5372
54- if param in string_params :
55- if isinstance (value ,list ):
56- value = ',' .join (value )
73+ return valid_q_string
74+
75+ if user_param .get ('raw_query' ):
76+ value = user_param ['raw_query' ]
5777 if not isinstance (value ,str ):
58- raise TypeError (f'{ param } should be of type string.' )
59- elif param in bool_params :
60- if not isinstance (value ,bool ):
61- raise TypeError (f'{ param } should be of type bool.' )
62- value = 1 if value == True else 0
63- elif param in int_params :
64- if not isinstance (value ,int ):
65- raise TypeError (f'{ param } should be of type int.' )
78+ raise TypeError ('raw_query should be of type string.' )
79+ return validate_url (url = value )
6680
67- return {param :value }
81+ valid_parms = {}
82+ for param ,value in user_param .items ():
83+ if not value :continue
84+ if param in string_params :
85+ if isinstance (value ,list ):
86+ value = ',' .join (value )
87+ if not isinstance (value ,str ):
88+ raise TypeError (f'{ param } should be of type string.' )
89+ elif param in bool_params :
90+ if not isinstance (value ,bool ):
91+ raise TypeError (f'{ param } should be of type bool.' )
92+ value = 1 if value == True else 0
93+ elif param in int_params :
94+ if not isinstance (value ,int ):
95+ raise TypeError (f'{ param } should be of type int.' )
96+
97+ valid_parms [param ] = value
98+
99+ return valid_parms
68100
69101 def __get_feeds (self ,url :str ,retry_count :int = None )-> dict :
70102 try :
@@ -157,7 +189,7 @@ def news_api(
157189 domainurl :Optional [Union [str , list ]]= None , excludedomain :Optional [Union [str , list ]]= None , timezone :Optional [str ]= None , full_content :Optional [bool ]= None ,
158190 image :Optional [bool ]= None , video :Optional [bool ]= None , prioritydomain :Optional [str ]= None , page :Optional [str ]= None , scroll :Optional [bool ]= False ,
159191 max_result :Optional [int ]= None , qInMeta :Optional [str ]= None , tag :Optional [Union [str ,list ]]= None , sentiment :Optional [str ]= None ,
160- region :Optional [Union [str ,list ]]= None ,excludefield :Optional [Union [str ,list ]]= None ,removeduplicate :Optional [bool ]= None
192+ region :Optional [Union [str ,list ]]= None ,excludefield :Optional [Union [str ,list ]]= None ,removeduplicate :Optional [bool ]= None , raw_query : Optional [ str ] = None
161193 )-> dict :
162194 """
163195 Sending GET request to the news api.
@@ -167,13 +199,9 @@ def news_api(
167199 params = {
168200 'apikey' :self .apikey ,'q' :q ,'qInTitle' :qInTitle ,'country' :country ,'category' :category ,'language' :language ,'domain' :domain ,'timeframe' :str (timeframe ) if timeframe else timeframe ,
169201 'size' :size ,'domainurl' :domainurl ,'excludedomain' :excludedomain ,'timezone' :timezone ,'full_content' :full_content ,'image' :image ,'video' :video ,'prioritydomain' :prioritydomain ,
170- 'page' :page ,'qInMeta' :qInMeta ,'tag' :tag , 'sentiment' :sentiment , 'region' :region ,'excludefield' :excludefield ,'removeduplicate' :removeduplicate
202+ 'page' :page ,'qInMeta' :qInMeta ,'tag' :tag , 'sentiment' :sentiment , 'region' :region ,'excludefield' :excludefield ,'removeduplicate' :removeduplicate , 'raw_query' : raw_query
171203 }
172- URL_parameters = {}
173- for key ,value in params .items ():
174- if value is not None :
175- URL_parameters .update (self .__validate_parms (param = key ,value = value ))
176-
204+ URL_parameters = self .__validate_parms (user_param = params )
177205 URL_parameters_encoded = urlencode (URL_parameters , quote_via = quote )
178206 if scroll == True :
179207 return self .__get_feeds_all (url = f'{ constants .LATEST_URL } ?{ URL_parameters_encoded } ' ,max_result = max_result )
@@ -186,7 +214,7 @@ def latest_api(
186214 domainurl :Optional [Union [str , list ]]= None , excludedomain :Optional [Union [str , list ]]= None , timezone :Optional [str ]= None , full_content :Optional [bool ]= None ,
187215 image :Optional [bool ]= None , video :Optional [bool ]= None , prioritydomain :Optional [str ]= None , page :Optional [str ]= None , scroll :Optional [bool ]= False ,
188216 max_result :Optional [int ]= None , qInMeta :Optional [str ]= None , tag :Optional [Union [str ,list ]]= None , sentiment :Optional [str ]= None ,
189- region :Optional [Union [str ,list ]]= None ,excludefield :Optional [Union [str ,list ]]= None ,removeduplicate :Optional [bool ]= None
217+ region :Optional [Union [str ,list ]]= None ,excludefield :Optional [Union [str ,list ]]= None ,removeduplicate :Optional [bool ]= None , raw_query : Optional [ str ] = None
190218 )-> dict :
191219 """
192220 Sending GET request to the latest api.
@@ -195,13 +223,9 @@ def latest_api(
195223 params = {
196224 'apikey' :self .apikey ,'q' :q ,'qInTitle' :qInTitle ,'country' :country ,'category' :category ,'language' :language ,'domain' :domain ,'timeframe' :str (timeframe ) if timeframe else timeframe ,
197225 'size' :size ,'domainurl' :domainurl ,'excludedomain' :excludedomain ,'timezone' :timezone ,'full_content' :full_content ,'image' :image ,'video' :video ,'prioritydomain' :prioritydomain ,
198- 'page' :page ,'qInMeta' :qInMeta ,'tag' :tag , 'sentiment' :sentiment , 'region' :region ,'excludefield' :excludefield ,'removeduplicate' :removeduplicate
226+ 'page' :page ,'qInMeta' :qInMeta ,'tag' :tag , 'sentiment' :sentiment , 'region' :region ,'excludefield' :excludefield ,'removeduplicate' :removeduplicate , 'raw_query' : raw_query
199227 }
200- URL_parameters = {}
201- for key ,value in params .items ():
202- if value is not None :
203- URL_parameters .update (self .__validate_parms (param = key ,value = value ))
204-
228+ URL_parameters = self .__validate_parms (user_param = params )
205229 URL_parameters_encoded = urlencode (URL_parameters , quote_via = quote )
206230 if scroll == True :
207231 return self .__get_feeds_all (url = f'{ constants .LATEST_URL } ?{ URL_parameters_encoded } ' ,max_result = max_result )
@@ -213,7 +237,7 @@ def archive_api(
213237 language :Optional [Union [str , list ]]= None , domain :Optional [Union [str , list ]]= None , size :Optional [int ]= None ,domainurl :Optional [Union [str , list ]]= None ,
214238 excludedomain :Optional [Union [str , list ]]= None , timezone :Optional [str ]= None , full_content :Optional [bool ]= None ,image :Optional [bool ]= None ,
215239 video :Optional [bool ]= None ,prioritydomain :Optional [str ]= None , page :Optional [str ]= None , scroll :Optional [bool ]= False , max_result :Optional [int ]= None ,
216- from_date :Optional [str ]= None , to_date :Optional [str ]= None , qInMeta :Optional [str ]= None , excludefield :Optional [Union [str ,list ]]= None
240+ from_date :Optional [str ]= None , to_date :Optional [str ]= None , qInMeta :Optional [str ]= None , excludefield :Optional [Union [str ,list ]]= None , raw_query : Optional [ str ] = None
217241 ) -> dict :
218242 """
219243 Sending GET request to the archive api
@@ -222,31 +246,22 @@ def archive_api(
222246 params = {
223247 'q' :q ,'qInTitle' :qInTitle ,'country' :country ,'category' :category ,'language' :language ,'domain' :domain ,'size' :size ,'domainurl' :domainurl ,'excludedomain' :excludedomain ,
224248 'timezone' :timezone ,'full_content' :full_content ,'image' :image ,'video' :video ,'prioritydomain' :prioritydomain ,'page' :page ,'from_date' :from_date ,'to_date' :to_date ,
225- 'apikey' :self .apikey ,'qInMeta' :qInMeta ,'excludefield' :excludefield
249+ 'apikey' :self .apikey ,'qInMeta' :qInMeta ,'excludefield' :excludefield , 'raw_query' : raw_query
226250 }
227- URL_parameters = {}
228- for key ,value in params .items ():
229- if value is not None :
230- URL_parameters .update (self .__validate_parms (param = key ,value = value ))
231-
251+ URL_parameters = self .__validate_parms (user_param = params )
232252 URL_parameters_encoded = urlencode (URL_parameters , quote_via = quote )
233253 if scroll == True :
234254 return self .__get_feeds_all (url = f'{ constants .ARCHIVE_URL } ?{ URL_parameters_encoded } ' ,max_result = max_result )
235255 else :
236256 return self .__get_feeds (url = f'{ constants .ARCHIVE_URL } ?{ URL_parameters_encoded } ' )
237257
238- def sources_api ( self , country :Optional [str ]= None , category :Optional [str ]= None , language :Optional [str ]= None , prioritydomain :Optional [str ]= None ):
258+ def sources_api ( self , country :Optional [str ]= None , category :Optional [str ]= None , language :Optional [str ]= None , prioritydomain :Optional [str ]= None , raw_query : Optional [ str ] = None ):
239259 """
240260 Sending GET request to the sources api
241261 For more information about parameters and input, Please visit our documentation page: https://newsdata.io/documentation
242262 """
243- URL_parameters = {}
244- params = {"apikey" :self .apikey , "country" :country , "category" :category , "language" :language , "prioritydomain" :prioritydomain }
245- URL_parameters = {}
246- for key ,value in params .items ():
247- if value is not None :
248- URL_parameters .update (self .__validate_parms (param = key ,value = value ))
249-
263+ params = {"apikey" :self .apikey , "country" :country , "category" :category , "language" :language , "prioritydomain" :prioritydomain ,'raw_query' :raw_query }
264+ URL_parameters = self .__validate_parms (user_param = params )
250265 URL_parameters_encoded = urlencode (URL_parameters , quote_via = quote )
251266 return self .__get_feeds (url = f'{ constants .SOURCES_URL } ?{ URL_parameters_encoded } ' )
252267
@@ -256,7 +271,7 @@ def crypto_api(
256271 timezone :Optional [str ]= None , full_content :Optional [bool ]= None ,image :Optional [bool ]= None , video :Optional [bool ]= None , prioritydomain :Optional [str ]= None ,
257272 page :Optional [str ]= None , scroll :Optional [bool ]= False ,max_result :Optional [int ]= None , qInMeta :Optional [str ]= None ,tag :Optional [Union [str ,list ]]= None ,
258273 sentiment :Optional [str ]= None ,coin :Optional [Union [str , list ]]= None ,excludefield :Optional [Union [str ,list ]]= None ,from_date :Optional [str ]= None ,
259- to_date :Optional [str ]= None ,removeduplicate :Optional [bool ]= None
274+ to_date :Optional [str ]= None ,removeduplicate :Optional [bool ]= None , raw_query : Optional [ str ] = None ,
260275 )-> dict :
261276 """
262277 Sending GET request to the crypto api
@@ -267,13 +282,9 @@ def crypto_api(
267282 'apikey' :self .apikey ,'q' :q ,'qInTitle' :qInTitle ,'language' :language ,'domain' :domain ,'size' :size ,'domainurl' :domainurl ,
268283 'excludedomain' :excludedomain ,'timezone' :timezone ,'full_content' :full_content ,'image' :image ,'video' :video ,'prioritydomain' :prioritydomain ,'page' :page ,
269284 'timeframe' :str (timeframe ) if timeframe else timeframe ,'qInMeta' :qInMeta ,'tag' :tag , 'sentiment' :sentiment ,'coin' :coin ,'excludefield' :excludefield ,
270- 'from_date' :from_date ,'to_date' :to_date ,'removeduplicate' :removeduplicate
285+ 'from_date' :from_date ,'to_date' :to_date ,'removeduplicate' :removeduplicate , 'raw_query' : raw_query
271286 }
272- URL_parameters = {}
273- for key ,value in params .items ():
274- if value is not None :
275- URL_parameters .update (self .__validate_parms (param = key ,value = value ))
276-
287+ URL_parameters = self .__validate_parms (user_param = params )
277288 URL_parameters_encoded = urlencode (URL_parameters , quote_via = quote )
278289 if scroll == True :
279290 return self .__get_feeds_all (url = f'{ constants .CRYPTO_URL } ?{ URL_parameters_encoded } ' ,max_result = max_result )
0 commit comments