1212import logging
1313import os
1414from pathlib import Path
15+ import sys
1516import traceback
1617from typing import Dict , List , Tuple
1718from zoneinfo import ZoneInfo
2425
2526# -- GLOBALS --
2627NAME = "pair_from_sources"
28+ TRACE = 5
2729logging .basicConfig (level = logging .INFO ,
2830 format = "%(asctime)s %(name)s(%(funcName)s) %(levelname)s: %(message)s" )
31+ logging .addLevelName (TRACE , "TRACE" )
2932logging .captureWarnings (True )
3033logger = logging .getLogger (NAME )
3134ogr .UseExceptions ()
@@ -63,6 +66,11 @@ def cli_arg_parser() -> argparse.Namespace:
6366 action = "store_true" ,
6467 help = "output more logs"
6568 )
69+ parser .add_argument ("-vv" , "--very_verbose" ,
70+ dest = "very_verbose" ,
71+ action = "store_true" ,
72+ help = "output even more logs"
73+ )
6674 return parser .parse_args ()
6775
6876def load_configuration (path : Path ) -> Dict :
@@ -107,47 +115,52 @@ def write_output(output_conf: Dict, out_link_list: List[Tuple]) -> None:
107115 update_list (List[Tuple]): list of (fid, geometry) of declarations to update
108116 declaration_pkey (str): name of the private key column for declarations
109117 """
118+ new_pairs_count = 0
110119 with psycopg .connect (output_conf ["_pg_string" ]) as conn :
111120 cur = conn .cursor ()
112121 try :
113122 with conn .transaction ():
114123 for link_obj in out_link_list :
124+ logger .log (TRACE , f"Treating pair { link_obj } ." )
115125 # Vérification d'existence du lien
116126 cur .execute (
117127 sql .SQL (
118128 "SELECT * FROM {table} WHERE {decl_key} = %s AND {dete_key} = %s"
119129 ).format (
120130 table = sql .Identifier (output_conf ["schema" ],
121131 output_conf ["tables" ]["links" ]),
122- decl_key = sql .Identifier (out_link_declar_fkey ),
123- dete_key = sql .Identifier (out_link_detect_fkey )
132+ decl_key = sql .Identifier ("declaration_id" ),
133+ dete_key = sql .Identifier ("detection_id" )
124134 ),
125135 (
126- link_obj [out_link_declar_fkey ],
127- link_obj [out_link_detect_fkey ]
136+ link_obj ["declaration_id" ],
137+ link_obj ["detection_id" ]
128138 )
129139 )
130140 result = cur .fetchone ()
131141 # Ajout si inexistant
132142 if result is None :
143+ logger .log (TRACE , f"Pair { link_obj } does not exist and will be inserted." )
133144 cur .execute (
134145 sql .SQL (
135146 "INSERT INTO {table} ({decl_key}, {dete_key}) VALUES (%s, %s)"
136147 ).format (
137148 table = sql .Identifier (output_conf ["schema" ],
138149 output_conf ["tables" ]["links" ]),
139- decl_key = sql .Identifier (out_link_declar_fkey ),
140- dete_key = sql .Identifier (out_link_detect_fkey )
150+ decl_key = sql .Identifier ("declaration_id" ),
151+ dete_key = sql .Identifier ("detection_id" )
141152 ),
142153 (
143- link_obj [out_link_declar_fkey ],
144- link_obj [out_link_detect_fkey ]
154+ link_obj ["declaration_id" ],
155+ link_obj ["detection_id" ]
145156 )
146157 )
158+ new_pairs_count += 1
147159 except Exception as exc :
148160 logger .error (traceback .format_exc ())
149161 conn .rollback ()
150162 raise exc
163+ logger .debug (f"{ new_pairs_count } new pairs inserted in database." )
151164
152165# -- MAIN FUNCTION --
153166def main () -> None :
@@ -163,58 +176,74 @@ def main() -> None:
163176 try :
164177 logger .info ("Start of declarations' pairing with detections." )
165178 cli_args = cli_arg_parser ()
166- if cli_args .verbose :
179+ log_level_description = "normal"
180+ if cli_args .very_verbose :
181+ logger .setLevel (logging .getLevelName ("TRACE" ))
182+ log_level_description = "very verbose"
183+ elif cli_args .verbose :
167184 logger .setLevel (logging .DEBUG )
185+ log_level_description = "verbose"
186+ logger .info (f"Logging level: '{ logger .getEffectiveLevel ()} ' ({ log_level_description } )" )
168187 # Read configuration
169- logger .debug ("Loading configuration..." )
188+ logger .info ("Loading configuration..." )
170189 configuration = load_configuration (cli_args .path )
171190 # OGR layers and spatial references
172- logger .debug ("Preparing OGR entities..." )
191+ logger .info ("Preparing OGR entities..." )
173192 latlon_sr_name_list = ['WGS 84' ]
174193 ogr_pg_connection = ogr .Open (("PG: " + configuration ["main_database" ]["_pg_string" ]))
175194 ## Declarations layer
176- declaration_table = "." .join (configuration ["main_database" ]["schema" ],
177- configuration ["main_database" ]["tables" ]["declararations" ] )
195+ declaration_table = "." .join (( configuration ["main_database" ]["schema" ],
196+ configuration ["main_database" ]["tables" ]["declarations" ]) )
178197 declaration_ogr_layer = ogr_pg_connection .GetLayerByName (declaration_table )
179198 if declaration_ogr_layer is None :
180199 raise Exception (f"Declaration layer '{ declaration_table } ' was not loaded." )
200+ logger .log (TRACE ,
201+ f"FID column for declaration layer: '{ declaration_ogr_layer .GetFIDColumn ()} '" )
181202 declaration_osr_sr = declaration_ogr_layer .GetSpatialRef ()
182203 if declaration_osr_sr is None :
183204 raise Exception (
184205 f"Spatial reference for declaration layer '{ declaration_table } ' was not found." )
185206 is_declaration_sr_latlon = (declaration_osr_sr .EPSGTreatsAsLatLong ()
186207 or declaration_osr_sr .GetName () in latlon_sr_name_list )
208+ logger .debug (f"Declarations layer's SRS: { declaration_osr_sr .GetName ()} " )
187209 ## Detections layer
188- detection_table = "." .join (configuration ["main_database" ]["schema" ],
189- configuration ["main_database" ]["tables" ]["detections" ])
210+ detection_table = "." .join (( configuration ["main_database" ]["schema" ],
211+ configuration ["main_database" ]["tables" ]["detections" ]))
190212 detection_ogr_layer = ogr_pg_connection .GetLayerByName (detection_table )
191213 if detection_ogr_layer is None :
192214 raise Exception (f"Detection layer '{ detection_table } ' was not loaded." )
215+ logger .log (TRACE ,
216+ f"FID column for detection layer: '{ detection_ogr_layer .GetFIDColumn ()} '" )
193217 detection_osr_sr = detection_ogr_layer .GetSpatialRef ()
194218 if detection_osr_sr is None :
195219 raise Exception (
196220 f"Spatial reference for detection layer '{ detection_table } ' was not found." )
197221 is_detection_sr_latlon = (detection_osr_sr .EPSGTreatsAsLatLong ()
198222 or detection_osr_sr .GetName () in latlon_sr_name_list )
223+ logger .debug (f"Detections layer's SRS: { detection_osr_sr .GetName ()} " )
199224 ## Pairing layer
200- pairing_table = "." .join (configuration ["main_database" ]["schema" ],
201- configuration ["main_database" ]["tables" ]["links" ])
225+ pairing_table = "." .join (( configuration ["main_database" ]["schema" ],
226+ configuration ["main_database" ]["tables" ]["links" ]))
202227 pairing_ogr_layer = ogr_pg_connection .GetLayerByName (pairing_table )
203228 if pairing_ogr_layer is None :
204229 raise Exception (f"Pairing layer '{ pairing_table } ' was not loaded." )
205230 ## Coordinates transformations
206231 coordinates_transformation = None
207232 need_coordinates_swap = False # True if the two spatial references use a different axis order
208233 if detection_osr_sr != declaration_osr_sr :
234+ logger .debug ("Coordinates transformation is necessary." )
209235 coordinates_transformation = osr .CoordinateTransformation (
210236 declaration_osr_sr , detection_osr_sr )
211237 need_coordinates_swap = (
212238 (is_detection_sr_latlon and not is_declaration_sr_latlon )
213239 or (is_declaration_sr_latlon and not is_detection_sr_latlon )
214240 )
241+ if need_coordinates_swap :
242+ logger .debug ("Axis order swapping is necessary for this transformation." )
215243 # Data fetching
216- logger .debug ("Fetching source data..." )
244+ logger .info ("Fetching source data..." )
217245 ## Declarations (with non-null geometries and installation dates)
246+ logger .debug ("Fetching declarations with non-null spatial and temproal attributes." )
218247 declaration_dict = {}
219248 for farm_feature in declaration_ogr_layer :
220249 farm_id = farm_feature .GetFID ()
@@ -231,17 +260,20 @@ def main() -> None:
231260 new_geom .SwapXY ()
232261 new_geom .Transform (coordinates_transformation )
233262 declaration_dict [farm_id ]["geom" ] = new_geom .Clone ()
263+ logger .debug (f"{ len (declaration_dict )} declarations fetched." )
234264 ## Detections
265+ logger .debug ("Fetching detections." )
235266 detection_dict = {}
236267 for farm_feature in detection_ogr_layer :
237268 farm_id = farm_feature .GetFID ()
238269 detection_dict [farm_id ] = {
239270 "millesime" : farm_feature .GetField ("millesime" ),
240271 }
241272 detection_dict [farm_id ]["geom" ] = farm_feature .geometry ().Clone ()
273+ logger .debug (f"{ len (detection_dict )} detections fetched." )
242274 ogr_pg_connection = None
243275 # Pairing
244- logger .debug ("Computing pairs..." )
276+ logger .info ("Computing pairs..." )
245277 out_link_list = []
246278 for detection_id in detection_dict .keys ():
247279 for declaration_id in declaration_dict .keys ():
@@ -258,10 +290,12 @@ def main() -> None:
258290 is_pair = geom_intersect_bool and time_intersect_bool
259291 if is_pair :
260292 link_obj = {}
261- link_obj [out_link_declar_fkey ] = declaration_id
262- link_obj [out_link_detect_fkey ] = detection_id
293+ link_obj ["declaration_id" ] = declaration_id
294+ link_obj ["detection_id" ] = detection_id
263295 out_link_list .append (link_obj )
264- logger .debug ("Writing pairs in database..." )
296+ logger .debug (f"{ len (out_link_list )} pairs. (Include previously existing pairs.)" )
297+ ## TODO? check if some previous pairs no longer exist?
298+ logger .info ("Writing pairs in database..." )
265299 write_output (configuration ["main_database" ], out_link_list )
266300 logger .info ("End of declarations' pairing with detections." )
267301 return 0
0 commit comments