11import  json 
22import  os 
33from  json .decoder  import  JSONDecodeError 
4- from  typing  import  List ,  Optional 
4+ from  typing  import  Optional 
55from  urllib .error  import  HTTPError , URLError 
66
77import  click   # type: ignore 
2222class  StacValidate :
2323    def  __init__ (
2424        self ,
25-         stac_file : str  =  None ,
25+         stac_file : Optional [str ] =  None ,
26+         item_collection : bool  =  False ,
27+         pages : Optional [int ] =  None ,
2628        recursive : bool  =  False ,
2729        max_depth : Optional [int ] =  None ,
2830        core : bool  =  False ,
@@ -35,6 +37,8 @@ def __init__(
3537        log : str  =  "" ,
3638    ):
3739        self .stac_file  =  stac_file 
40+         self .item_collection  =  item_collection 
41+         self .pages  =  pages 
3842        self .message : list  =  []
3943        self .custom  =  custom 
4044        self .links  =  links 
@@ -64,10 +68,10 @@ def create_err_msg(self, err_type: str, err_msg: str) -> dict:
6468        }
6569
6670    def  create_links_message (self ):
67-         format_valid :  List [ str ]  =  []
68-         format_invalid :  List [ str ]  =  []
69-         request_valid :  List [ str ]  =  []
70-         request_invalid :  List [ str ]  =  []
71+         format_valid  =  []
72+         format_invalid  =  []
73+         request_valid  =  []
74+         request_invalid  =  []
7175        return  {
7276            "format_valid" : format_valid ,
7377            "format_invalid" : format_invalid ,
@@ -267,75 +271,106 @@ def recursive_validator(self, stac_type: str) -> bool:
267271                        click .echo (json .dumps (message , indent = 4 ))
268272        return  True 
269273
270-     def  validate_dict (cls , stac_content ):
271-         cls .stac_content  =  stac_content 
272-         return  cls .run ()
274+     def  validate_dict (self , stac_content ):
275+         self .stac_content  =  stac_content 
276+         return  self .run ()
273277
274-     def  run (cls ):
278+     def  validate_item_collection_dict (self , item_collection ):
279+         for  item  in  item_collection ["features" ]:
280+             self .custom  =  "" 
281+             self .validate_dict (item )
282+ 
283+     def  validate_item_collection (self ):
284+         page  =  1 
285+         print (f"processing page { page }  " )
286+         item_collection  =  fetch_and_parse_file (self .stac_file )
287+         self .validate_item_collection_dict (item_collection )
288+         try :
289+             if  self .pages  is  not   None :
290+                 for  _  in  range (self .pages  -  1 ):
291+                     if  "links"  in  item_collection :
292+                         for  link  in  item_collection ["links" ]:
293+                             if  link ["rel" ] ==  "next" :
294+                                 page  =  page  +  1 
295+                                 print (f"processing page { page }  " )
296+                                 next_link  =  link ["href" ]
297+                                 self .stac_file  =  next_link 
298+                                 item_collection  =  fetch_and_parse_file (self .stac_file )
299+                                 self .validate_item_collection_dict (item_collection )
300+                                 break 
301+         except  Exception  as  e :
302+             message  =  {}
303+             message ["pagination_error" ] =  (
304+                 f"Validating the item collection failed on page { page }  : " ,
305+                 str (e ),
306+             )
307+             self .message .append (message )
308+ 
309+     def  run (self ):
275310        message  =  {}
276311        try :
277-             if  cls .stac_file  is  not   None :
278-                 cls .stac_content  =  fetch_and_parse_file (cls .stac_file )
279-             stac_type  =  get_stac_type (cls .stac_content ).upper ()
280-             cls .version  =  cls .stac_content ["stac_version" ]
312+             if  self .stac_file  is  not   None   and   self . item_collection   is   False :
313+                 self .stac_content  =  fetch_and_parse_file (self .stac_file )
314+             stac_type  =  get_stac_type (self .stac_content ).upper ()
315+             self .version  =  self .stac_content ["stac_version" ]
281316
282-             if  cls .core  is  True :
283-                 message  =  cls .create_message (stac_type , "core" )
284-                 cls .core_validator (stac_type )
285-                 message ["schema" ] =  [cls .custom ]
286-                 cls .valid  =  True 
287-             elif  cls .custom  !=  "" :
288-                 message  =  cls .create_message (stac_type , "custom" )
289-                 message ["schema" ] =  [cls .custom ]
290-                 cls .custom_validator ()
291-                 cls .valid  =  True 
292-             elif  cls .recursive :
293-                 cls .valid  =  cls .recursive_validator (stac_type )
294-             elif  cls .extensions  is  True :
295-                 message  =  cls .extensions_validator (stac_type )
317+             if  self .core  is  True :
318+                 message  =  self .create_message (stac_type , "core" )
319+                 self .core_validator (stac_type )
320+                 message ["schema" ] =  [self .custom ]
321+                 self .valid  =  True 
322+             elif  self .custom  !=  "" :
323+                 message  =  self .create_message (stac_type , "custom" )
324+                 message ["schema" ] =  [self .custom ]
325+                 self .custom_validator ()
326+                 self .valid  =  True 
327+             elif  self .recursive :
328+                 self .valid  =  self .recursive_validator (stac_type )
329+             elif  self .extensions  is  True :
330+                 message  =  self .extensions_validator (stac_type )
296331            else :
297-                 cls .valid  =  True 
298-                 message  =  cls .default_validator (stac_type )
332+                 self .valid  =  True 
333+                 message  =  self .default_validator (stac_type )
299334
300335        except  URLError  as  e :
301-             message .update (cls .create_err_msg ("URLError" , str (e )))
336+             message .update (self .create_err_msg ("URLError" , str (e )))
302337        except  JSONDecodeError  as  e :
303-             message .update (cls .create_err_msg ("JSONDecodeError" , str (e )))
338+             message .update (self .create_err_msg ("JSONDecodeError" , str (e )))
304339        except  ValueError  as  e :
305-             message .update (cls .create_err_msg ("ValueError" , str (e )))
340+             message .update (self .create_err_msg ("ValueError" , str (e )))
306341        except  TypeError  as  e :
307-             message .update (cls .create_err_msg ("TypeError" , str (e )))
342+             message .update (self .create_err_msg ("TypeError" , str (e )))
308343        except  FileNotFoundError  as  e :
309-             message .update (cls .create_err_msg ("FileNotFoundError" , str (e )))
344+             message .update (self .create_err_msg ("FileNotFoundError" , str (e )))
310345        except  ConnectionError  as  e :
311-             message .update (cls .create_err_msg ("ConnectionError" , str (e )))
346+             message .update (self .create_err_msg ("ConnectionError" , str (e )))
312347        except  exceptions .SSLError  as  e :
313-             message .update (cls .create_err_msg ("SSLError" , str (e )))
348+             message .update (self .create_err_msg ("SSLError" , str (e )))
314349        except  OSError  as  e :
315-             message .update (cls .create_err_msg ("OSError" , str (e )))
350+             message .update (self .create_err_msg ("OSError" , str (e )))
316351        except  jsonschema .exceptions .ValidationError  as  e :
317352            if  e .absolute_path :
318353                err_msg  =  f"{ e .message }  . Error is in { ' -> ' .join ([str (i ) for  i  in  e .absolute_path ])}   " 
319354            else :
320355                err_msg  =  f"{ e .message }   of the root of the STAC object" 
321-             message .update (cls .create_err_msg ("JSONSchemaValidationError" , err_msg ))
356+             message .update (self .create_err_msg ("JSONSchemaValidationError" , err_msg ))
322357        except  KeyError  as  e :
323-             message .update (cls .create_err_msg ("KeyError" , str (e )))
358+             message .update (self .create_err_msg ("KeyError" , str (e )))
324359        except  HTTPError  as  e :
325-             message .update (cls .create_err_msg ("HTTPError" , str (e )))
360+             message .update (self .create_err_msg ("HTTPError" , str (e )))
326361        except  Exception  as  e :
327-             message .update (cls .create_err_msg ("Exception" , str (e )))
362+             message .update (self .create_err_msg ("Exception" , str (e )))
328363
329364        if  len (message ) >  0 :
330-             message ["valid_stac" ] =  cls .valid 
331-             cls .message .append (message )
365+             message ["valid_stac" ] =  self .valid 
366+             self .message .append (message )
332367
333-         if  cls .log  !=  "" :
334-             f  =  open (cls .log , "w" )
335-             f .write (json .dumps (cls .message , indent = 4 ))
368+         if  self .log  !=  "" :
369+             f  =  open (self .log , "w" )
370+             f .write (json .dumps (self .message , indent = 4 ))
336371            f .close ()
337372
338-         if  cls .valid :
373+         if  self .valid :
339374            return  True 
340375        else :
341376            return  False 
0 commit comments