66import tempfile
77import zipfile
88from pathlib import Path
9+ import logging
910
1011import geopandas as gpd
1112from django .contrib .gis .geos import MultiLineString , LineString
1213from django .core .exceptions import ValidationError
1314
15+ # Create a logger for this module
16+ logger = logging .getLogger (__name__ )
17+
1418
1519def check_gis_environment ():
1620 """
@@ -22,20 +26,20 @@ def check_gis_environment():
2226 import tempfile
2327 import os
2428
25- print ("=== GIS Environment Check ===" )
26- print (f"GeoPandas version: { gpd .__version__ } " )
27- print (f"Fiona version: { fiona .__version__ } " )
28- print (f"Supported drivers: { list (fiona .supported_drivers .keys ())} " )
29- print (f"KML driver available: { 'KML' in fiona .supported_drivers } " )
30- print (f"Temp directory: { tempfile .gettempdir ()} " )
31- print (f"Temp dir writable: { os .access (tempfile .gettempdir (), os .W_OK )} " )
29+ logger . info ("=== GIS Environment Check ===" )
30+ logger . info (f"GeoPandas version: { gpd .__version__ } " )
31+ logger . info (f"Fiona version: { fiona .__version__ } " )
32+ logger . info (f"Supported drivers: { list (fiona .supported_drivers .keys ())} " )
33+ logger . info (f"KML driver available: { 'KML' in fiona .supported_drivers } " )
34+ logger . info (f"Temp directory: { tempfile .gettempdir ()} " )
35+ logger . info (f"Temp dir writable: { os .access (tempfile .gettempdir (), os .W_OK )} " )
3236
3337 # Test creating a temp file
3438 try :
3539 with tempfile .NamedTemporaryFile (suffix = ".kml" ) as tmp :
36- print (f"Can create temp files: True ({ tmp .name } )" )
40+ logger . info (f"Can create temp files: True ({ tmp .name } )" )
3741 except Exception as e :
38- print (f"Cannot create temp files: { e } " )
42+ logger . error (f"Cannot create temp files: { e } " )
3943
4044 return True
4145
@@ -115,13 +119,13 @@ def read_kmz_file(kmz_path):
115119 Returns:
116120 GeoDataFrame: Combined data from all KML files in the KMZ
117121 """
118- print (f"DEBUG: Reading KMZ file: { kmz_path } " )
122+ logger . debug (f"π Reading KMZ file: { kmz_path } " )
119123 try :
120124 # First, try direct GeoPandas reading (works for simple KMZ files)
121- print (f"DEBUG: Attempting direct read of { kmz_path } " )
125+ logger . debug (f"π Attempting direct read of { kmz_path } " )
122126 return gpd .read_file (kmz_path )
123127 except Exception as e :
124- print (f"Direct KMZ reading failed: { e } . Trying extraction method..." )
128+ logger . warning (f"π Direct KMZ reading failed: { e } . Trying extraction method..." )
125129 return _read_kmz_by_extraction (kmz_path )
126130
127131
@@ -131,19 +135,19 @@ def _read_kmz_by_extraction(kmz_path):
131135 """
132136 temp_dir = None
133137 try :
134- print (f"DEBUG: Starting KMZ extraction from { kmz_path } " )
135- print (f"DEBUG: KMZ file exists: { Path (kmz_path ).exists ()} " )
136- print (f"DEBUG: KMZ file size: { Path (kmz_path ).stat ().st_size if Path (kmz_path ).exists () else 'N/A' } bytes" )
138+ logger . debug (f"π Starting KMZ extraction from { kmz_path } " )
139+ logger . debug (f"π KMZ file exists: { Path (kmz_path ).exists ()} " )
140+ logger . debug (f"π KMZ file size: { Path (kmz_path ).stat ().st_size if Path (kmz_path ).exists () else 'N/A' } bytes" )
137141
138142 # Create temporary directory for extraction with explicit permissions
139143 temp_dir = tempfile .mkdtemp (prefix = "kmz_extract_" )
140144 os .chmod (temp_dir , 0o755 ) # Ensure proper permissions
141- print (f"DEBUG: Created temp directory: { temp_dir } " )
142- print (f"DEBUG: Temp dir writable: { os .access (temp_dir , os .W_OK )} " )
145+ logger . debug (f"π Created temp directory: { temp_dir } " )
146+ logger . debug (f"π Temp dir writable: { os .access (temp_dir , os .W_OK )} " )
143147
144148 # Extract all KML files from KMZ
145149 kml_files = extract_all_kml_from_kmz (kmz_path , temp_dir )
146- print (f"DEBUG: Extracted KML files: { kml_files } " )
150+ logger . debug (f"π Extracted KML files: { kml_files } " )
147151
148152 if not kml_files :
149153 raise ValidationError ("No KML files found in KMZ archive" )
@@ -152,44 +156,46 @@ def _read_kmz_by_extraction(kmz_path):
152156 all_gdfs = []
153157 for kml_file in kml_files :
154158 try :
155- print (f"DEBUG: Processing KML file: { Path (kml_file ).name } " )
156- print (f"DEBUG: KML file exists: { Path (kml_file ).exists ()} " )
157- print (
158- f"DEBUG: KML file size: { Path (kml_file ).stat ().st_size if Path (kml_file ).exists () else 'N/A' } bytes"
159+ logger .debug (f"π Processing KML file: { Path (kml_file ).name } " )
160+ logger .debug (f"π KML file exists: { Path (kml_file ).exists ()} " )
161+ logger .debug (
162+ f"π KML file size: { Path (kml_file ).stat ().st_size if Path (kml_file ).exists () else 'N/A' } bytes"
163+ )
164+ logger .debug (
165+ f"π KML file readable: { os .access (kml_file , os .R_OK ) if Path (kml_file ).exists () else 'N/A' } "
159166 )
160- print (f"DEBUG: KML file readable: { os .access (kml_file , os .R_OK ) if Path (kml_file ).exists () else 'N/A' } " )
161167
162168 # Read all layers from this KML file
163169 layer_gdfs = read_all_kml_layers (kml_file )
164- print (f"DEBUG: Got { len (layer_gdfs )} layer(s) from { Path (kml_file ).name } " )
170+ logger . debug (f"π Got { len (layer_gdfs )} layer(s) from { Path (kml_file ).name } " )
165171 all_gdfs .extend (layer_gdfs )
166- print (f"Successfully loaded { len (layer_gdfs )} layer(s) from { Path (kml_file ).name } " )
172+ logger . info (f"π Successfully loaded { len (layer_gdfs )} layer(s) from { Path (kml_file ).name } " )
167173 except Exception as e :
168- print (f"ERROR: Could not load { kml_file } : { e } " )
169- print (f"ERROR: Exception type: { type (e )} " )
174+ logger . error (f"π Could not load { kml_file } : { e } " )
175+ logger . error (f"π Exception type: { type (e )} " )
170176 import traceback
171177
172- print (f"ERROR: Traceback: { traceback .format_exc ()} " )
178+ logger . error (f"π Traceback: { traceback .format_exc ()} " )
173179 continue
174180
175- print (f"DEBUG: Total GeoDataFrames collected: { len (all_gdfs )} " )
181+ logger . debug (f"π Total GeoDataFrames collected: { len (all_gdfs )} " )
176182
177183 if not all_gdfs :
178184 # Additional debugging before raising error
179- print ( "ERROR: No GeoDataFrames were successfully created" )
180- print (f"ERROR: Original KML files found: { kml_files } " )
185+ logger . error ( "π No GeoDataFrames were successfully created" )
186+ logger . error (f"π Original KML files found: { kml_files } " )
181187 for kml_file in kml_files :
182188 if Path (kml_file ).exists ():
183- print (f"ERROR: { kml_file } exists with size { Path (kml_file ).stat ().st_size } " )
189+ logger . error (f"π { kml_file } exists with size { Path (kml_file ).stat ().st_size } " )
184190 # Try to read first few lines
185191 try :
186192 with open (kml_file , "r" , encoding = "utf-8" ) as f :
187193 first_lines = f .read (500 )
188- print (f"ERROR: First 500 chars of { Path (kml_file ).name } : { repr (first_lines )} " )
194+ logger . error (f"π First 500 chars of { Path (kml_file ).name } : { repr (first_lines )} " )
189195 except Exception as read_error :
190- print (f"ERROR: Could not read KML file content: { read_error } " )
196+ logger . error (f"π Could not read KML file content: { read_error } " )
191197 else :
192- print (f"ERROR: { kml_file } does not exist after extraction" )
198+ logger . error (f"π { kml_file } does not exist after extraction" )
193199
194200 raise ValidationError ("Could not load any layers from the KMZ archive" )
195201
@@ -199,18 +205,20 @@ def _read_kmz_by_extraction(kmz_path):
199205 else :
200206 # Concatenate all GeoDataFrames
201207 combined_gdf = gpd .GeoDataFrame (gpd .pd .concat (all_gdfs , ignore_index = True ), crs = all_gdfs [0 ].crs )
202- print (f"Combined { len (all_gdfs )} layer(s) into single GeoDataFrame with { len (combined_gdf )} total features" )
208+ logger .info (
209+ f"π Combined { len (all_gdfs )} layer(s) into single GeoDataFrame with { len (combined_gdf )} total features"
210+ )
203211
204212 return combined_gdf
205213
206214 except ValidationError :
207215 raise # Re-raise validation errors as-is
208216 except Exception as e :
209- print (f"ERROR: Unexpected error in _read_kmz_by_extraction: { e } " )
210- print (f"ERROR: Exception type: { type (e )} " )
217+ logger . error (f"π Unexpected error in _read_kmz_by_extraction: { e } " )
218+ logger . error (f"π Exception type: { type (e )} " )
211219 import traceback
212220
213- print (f"ERROR: Full traceback: { traceback .format_exc ()} " )
221+ logger . error (f"π Full traceback: { traceback .format_exc ()} " )
214222 raise ValidationError (f"Failed to extract KMZ file: { str (e )} " )
215223
216224 finally :
@@ -220,9 +228,9 @@ def _read_kmz_by_extraction(kmz_path):
220228 import shutil
221229
222230 shutil .rmtree (temp_dir , ignore_errors = True )
223- print (f"DEBUG: Cleaned up temp directory: { temp_dir } " )
231+ logger . debug (f"π Cleaned up temp directory: { temp_dir } " )
224232 except Exception as cleanup_error :
225- print (f"WARNING: Could not clean up temp directory { temp_dir } : { cleanup_error } " )
233+ logger . warning (f"π Could not clean up temp directory { temp_dir } : { cleanup_error } " )
226234
227235
228236def read_all_kml_layers (kml_file ):
@@ -240,78 +248,78 @@ def read_all_kml_layers(kml_file):
240248 layer_gdfs = []
241249
242250 try :
243- print (f"DEBUG: Attempting to read layers from { kml_file } " )
244- print (f"DEBUG: File exists: { Path (kml_file ).exists ()} " )
251+ logger . debug (f"π Attempting to read layers from { kml_file } " )
252+ logger . debug (f"π File exists: { Path (kml_file ).exists ()} " )
245253
246254 if not Path (kml_file ).exists ():
247- print (f"ERROR: KML file does not exist: { kml_file } " )
255+ logger . error (f"π KML file does not exist: { kml_file } " )
248256 return layer_gdfs
249257
250258 # Get all layer names from the KML file
251259 try :
252260 layers = fiona .listlayers (kml_file )
253- print (f"Found { len (layers )} layer(s) in { Path (kml_file ).name } : { layers } " )
261+ logger . debug (f"π Found { len (layers )} layer(s) in { Path (kml_file ).name } : { layers } " )
254262 except Exception as list_error :
255- print (f"ERROR: Could not list layers in { kml_file } : { list_error } " )
256- print (f"ERROR: fiona.listlayers exception type: { type (list_error )} " )
263+ logger . error (f"π Could not list layers in { kml_file } : { list_error } " )
264+ logger . error (f"π fiona.listlayers exception type: { type (list_error )} " )
257265 # Try fallback immediately
258266 layers = []
259267
260268 if layers :
261269 for layer_name in layers :
262270 try :
263- print (f"DEBUG: Reading layer '{ layer_name } '" )
271+ logger . debug (f"π Reading layer '{ layer_name } '" )
264272 # Read each layer explicitly
265273 gdf = gpd .read_file (kml_file , layer = layer_name )
266274 if not gdf .empty :
267275 # Add metadata about source
268276 gdf ["source_kml" ] = Path (kml_file ).name
269277 gdf ["source_layer" ] = layer_name
270278 layer_gdfs .append (gdf )
271- print (
272- f" Layer '{ layer_name } ': { len (gdf )} features, geometry types: { gdf .geometry .geom_type .value_counts ().to_dict ()} "
279+ logger . debug (
280+ f"π Layer '{ layer_name } ': { len (gdf )} features, geometry types: { gdf .geometry .geom_type .value_counts ().to_dict ()} "
273281 )
274282 else :
275- print (f" Layer '{ layer_name } ': empty" )
283+ logger . debug (f"π Layer '{ layer_name } ': empty" )
276284 except Exception as layer_error :
277- print (f" ERROR: Could not read layer '{ layer_name } ': { layer_error } " )
278- print (f" ERROR: Layer read exception type: { type (layer_error )} " )
285+ logger . error (f"π Could not read layer '{ layer_name } ': { layer_error } " )
286+ logger . error (f"π Layer read exception type: { type (layer_error )} " )
279287 continue
280288 else :
281- print ( " No layers found or layer listing failed, trying default read" )
289+ logger . debug ( "π No layers found or layer listing failed, trying default read" )
282290
283291 # Fallback to default reading if no layers were processed or layer listing failed
284292 if not layer_gdfs :
285293 try :
286- print (f"DEBUG: Attempting default read of { kml_file } " )
294+ logger . debug (f"π Attempting default read of { kml_file } " )
287295 gdf = gpd .read_file (kml_file )
288296 if not gdf .empty :
289297 gdf ["source_kml" ] = Path (kml_file ).name
290298 gdf ["source_layer" ] = "default"
291299 layer_gdfs .append (gdf )
292- print (f"Default read successful: { len (gdf )} features" )
300+ logger . debug (f"π Default read successful: { len (gdf )} features" )
293301 else :
294- print ( " Default read returned empty GeoDataFrame" )
302+ logger . debug ( "π Default read returned empty GeoDataFrame" )
295303 except Exception as fallback_error :
296- print (f"ERROR: Fallback read also failed: { fallback_error } " )
297- print (f"ERROR: Fallback exception type: { type (fallback_error )} " )
304+ logger . error (f"π Fallback read also failed: { fallback_error } " )
305+ logger . error (f"π Fallback exception type: { type (fallback_error )} " )
298306
299307 # Try to diagnose the issue
300308 try :
301309 with open (kml_file , "r" , encoding = "utf-8" ) as f :
302310 content_sample = f .read (1000 )
303- print (f"ERROR: KML file content sample (first 1000 chars): { repr (content_sample )} " )
311+ logger . error (f"π KML file content sample (first 1000 chars): { repr (content_sample )} " )
304312 except Exception as read_error :
305- print (f"ERROR: Could not even read KML file as text: { read_error } " )
313+ logger . error (f"π Could not even read KML file as text: { read_error } " )
306314
307315 except Exception as outer_error :
308- print (f"ERROR: Outer exception in read_all_kml_layers: { outer_error } " )
309- print (f"ERROR: Outer exception type: { type (outer_error )} " )
316+ logger . error (f"π Outer exception in read_all_kml_layers: { outer_error } " )
317+ logger . error (f"π Outer exception type: { type (outer_error )} " )
310318 import traceback
311319
312- print (f"ERROR: Full traceback: { traceback .format_exc ()} " )
320+ logger . error (f"π Full traceback: { traceback .format_exc ()} " )
313321
314- print (f"DEBUG: Returning { len (layer_gdfs )} layer GeoDataFrames" )
322+ logger . debug (f"π Returning { len (layer_gdfs )} layer GeoDataFrames" )
315323 return layer_gdfs
316324
317325
@@ -335,7 +343,7 @@ def extract_all_kml_from_kmz(kmz_path, output_dir):
335343 if not kml_files :
336344 raise FileNotFoundError ("No .kml files found in KMZ archive" )
337345
338- print (f"Found { len (kml_files )} KML file(s) in KMZ: { kml_files } " )
346+ logger . debug (f"π Found { len (kml_files )} KML file(s) in KMZ: { kml_files } " )
339347
340348 for kml_file in kml_files :
341349 # Generate unique output filename to avoid conflicts
@@ -360,7 +368,7 @@ def extract_all_kml_from_kmz(kmz_path, output_dir):
360368 out_file .write (kml_content .read ())
361369
362370 extracted_files .append (str (output_path ))
363- print (f"Extracted: { kml_file } -> { output_path } " )
371+ logger . debug (f"π Extracted: { kml_file } -> { output_path } " )
364372
365373 return extracted_files
366374
@@ -380,9 +388,9 @@ def gdf_to_multilinestring(gdf):
380388 raise ValidationError ("No geometry found in the file" )
381389
382390 # Debug information
383- print (f"GeoDataFrame info: { len (gdf )} features" )
384- print (f"Geometry types: { gdf .geometry .geom_type .value_counts ().to_dict ()} " )
385- print (f"CRS: { gdf .crs } " )
391+ logger . debug (f"π GeoDataFrame info: { len (gdf )} features" )
392+ logger . debug (f"π Geometry types: { gdf .geometry .geom_type .value_counts ().to_dict ()} " )
393+ logger . debug (f"π CRS: { gdf .crs } " )
386394
387395 # Filter for LineString and MultiLineString geometries
388396 line_geometries = gdf [gdf .geometry .geom_type .isin (["LineString" , "MultiLineString" ])]
@@ -421,13 +429,13 @@ def gdf_to_multilinestring(gdf):
421429 linestrings .append (LineString (coords_2d , srid = 4326 ))
422430
423431 except Exception as e :
424- print (f"Error processing geometry { idx } : { e } " )
432+ logger . error (f"π Error processing geometry { idx } : { e } " )
425433 continue
426434
427435 if not linestrings :
428436 raise ValidationError ("No valid line geometries could be extracted from the file. Please check file structure." )
429437
430- print (f"Successfully extracted { len (linestrings )} line segments (converted to 2D)" )
438+ logger . info (f"π Successfully extracted { len (linestrings )} line segments (converted to 2D)" )
431439
432440 # Create MultiLineString from all collected LineStrings
433441 return MultiLineString (* linestrings )
@@ -457,7 +465,7 @@ def validate_path_geometry(geometry):
457465 if geometry .num_geom == 0 :
458466 raise ValidationError ("MultiLineString contains no line segments. Please Check GeoJSON structure." )
459467
460- print (f"Geometry validation passed: { geometry .num_geom } segments, valid={ geometry .valid } " )
468+ logger . info (f"π Geometry validation passed: { geometry .num_geom } segments, valid={ geometry .valid } " )
461469
462470
463471def ensure_2d_geometry (geometry ):
0 commit comments