1010"""
1111
1212import argparse
13+ import logging
1314import os
1415import re
1516import sys
1617from collections import Counter
1718
19+ # Configure logging
20+ logging .basicConfig (
21+ level = logging .INFO ,
22+ format = '%(levelname)s: %(message)s' ,
23+ handlers = [logging .StreamHandler (sys .stderr )]
24+ )
25+ logger = logging .getLogger (__name__ )
26+
1827try :
1928 import griffe
2029 try :
2130 from griffe .dataclasses import Object
2231 except (ImportError , AttributeError ):
2332 from griffe import Object
2433except ImportError as e :
25- print (f"ERROR: griffe not installed: { e } " , file = sys . stderr )
26- print ("Install with: pip install griffe" , file = sys . stderr )
34+ logger . error (f"griffe not installed: { e } " )
35+ logger . error ("Install with: pip install griffe" )
2736 sys .exit (2 )
2837
2938# Configure UTF-8 for Windows
@@ -98,7 +107,7 @@ def visit(obj, path, depth=0, is_root=False):
98107 # Check for exempt decorator
99108 if has_exempt_decorator (obj ):
100109 filtered .add (current_path )
101- print (f" ⏭️ Exempt: { current_path } " , file = sys . stderr )
110+ logger . info (f" ⏭️ Exempt: { current_path } " )
102111
103112 # Visit children
104113 if hasattr (obj , 'members' ):
@@ -244,17 +253,17 @@ def main():
244253 try :
245254 package_name = args .package
246255
247- print (f"\n { '=' * 80 } \n API COMPATIBILITY CHECK: { package_name } \n { '=' * 80 } \n " , file = sys . stderr )
256+ logger . info (f"\n { '=' * 80 } \n API COMPATIBILITY CHECK: { package_name } \n { '=' * 80 } \n " )
248257
249258 # Load baseline
250- print (f"📦 Loading baseline @ { args .baseline } ..." , file = sys . stderr )
259+ logger . info (f"📦 Loading baseline @ { args .baseline } ..." )
251260 baseline = griffe .load_git (
252261 package_name , ref = args .baseline , resolve_aliases = False ,
253262 resolve_external = False , allow_inspection = False )
254- print (f" ✓ Loaded" , file = sys . stderr )
263+ logger . info (f" ✓ Loaded" )
255264
256265 # Load current
257- print (f"\n 📦 Loading current @ { args .current or 'working directory' } ..." , file = sys . stderr )
266+ logger . info (f"\n 📦 Loading current @ { args .current or 'working directory' } ..." )
258267 if args .current :
259268 current = griffe .load_git (
260269 package_name , ref = args .current , resolve_aliases = False ,
@@ -263,61 +272,61 @@ def main():
263272 current = griffe .load (
264273 package_name , search_paths = [os .getcwd ()], resolve_aliases = False ,
265274 resolve_external = False , allow_inspection = False )
266- print (f" ✓ Loaded" , file = sys . stderr )
275+ logger . info (f" ✓ Loaded" )
267276
268277 # Get filtered paths from CURRENT version only
269- print (f"\n 🔍 Finding exempt objects in current version..." , file = sys . stderr )
278+ logger . info (f"\n 🔍 Finding exempt objects in current version..." )
270279 filtered_paths = get_filtered_paths (current , package_name )
271- print (f" Found { len (filtered_paths )} exempt objects" , file = sys . stderr )
280+ logger . info (f" Found { len (filtered_paths )} exempt objects" )
272281
273282 # Find breaking changes
274- print (f"\n 🔍 Comparing versions..." , file = sys . stderr )
283+ logger . info (f"\n 🔍 Comparing versions..." )
275284 all_changes = list (griffe .find_breaking_changes (baseline , current ))
276- print (f" Found { len (all_changes )} potential breaking changes" , file = sys . stderr )
285+ logger . info (f" Found { len (all_changes )} potential breaking changes" )
277286
278287 # Filter out exempt changes
279288 breaking_changes = []
280289 skipped_count = 0
281290
282- # DEBUG: Print first 5 breaking changes to STDOUT for debugging
283- print ("\n ===TEST DEBUG (first 5 changes)===" , flush = True )
284- print (f"Filtered paths: { filtered_paths } " , flush = True )
291+ # DEBUG: Print first 5 breaking changes for debugging
292+ print ("\n ===TEST DEBUG (first 5 changes)===" )
293+ print (f"Filtered paths: { filtered_paths } " )
285294 for i , change in enumerate (all_changes [:5 ]):
286295 path = get_object_path (change )
287296 clean_path = path .split ('(' )[0 ] if path and '(' in path else path
288- print (f"\n Change { i + 1 } : { path } " , flush = True )
289- print (f" Clean: { clean_path } " , flush = True )
290- print (f" Clean repr: { repr (clean_path )} " , flush = True )
297+ print (f"\n Change { i + 1 } : { path } " )
298+ print (f" Clean: { clean_path } " )
299+ print (f" Clean repr: { repr (clean_path )} " )
291300
292301 # Test matching
293302 matched = False
294303 for fpath in filtered_paths :
295304 if clean_path and (clean_path == fpath or clean_path .startswith (fpath + '.' )):
296- print (f" ✓ MATCH with: { fpath } " , flush = True )
305+ print (f" ✓ MATCH with: { fpath } " )
297306 matched = True
298307 break
299308 if not matched :
300- print (f" ✗ NO MATCH" , flush = True )
301- print ("\n ===END TEST DEBUG===\n " , flush = True )
309+ print (f" ✗ NO MATCH" )
310+ print ("\n ===END TEST DEBUG===\n " )
302311
303312 for change in all_changes :
304313 if should_skip_change (change , filtered_paths ):
305314 skipped_count += 1
306315 else :
307316 breaking_changes .append (change )
308317
309- print (f"\n Skipped { skipped_count } exempt | Reporting { len (breaking_changes )} breaking changes" , file = sys . stderr )
318+ logger . info (f"\n Skipped { skipped_count } exempt | Reporting { len (breaking_changes )} breaking changes" )
310319
311320 # Print results
312321 if not breaking_changes :
313- print (f"\n ✅ No breaking changes detected!" , file = sys . stderr )
322+ logger . info (f"\n ✅ No breaking changes detected!" )
314323 return 0
315324
316325 # Count by type
317326 change_types = Counter (change .kind .value for change in breaking_changes )
318- print (f"\n 📊 Breaking changes by type:" , file = sys . stderr )
327+ logger . info (f"\n 📊 Breaking changes by type:" )
319328 for change_type , count in sorted (change_types .items (), key = lambda x : - x [1 ]):
320- print (f" • { change_type } : { count } " , file = sys . stderr )
329+ logger . info (f" • { change_type } : { count } " )
321330
322331 # Print detailed changes
323332 print (f"\n ❌ Found { len (breaking_changes )} breaking change(s):\n { '=' * 80 } " )
@@ -332,7 +341,7 @@ def main():
332341 return 1
333342
334343 except Exception as e :
335- print (f"\n ❌ Error: { e } " , file = sys . stderr )
344+ logger . error (f"\n ❌ Error: { e } " )
336345 if args .verbose :
337346 import traceback
338347 traceback .print_exc ()
0 commit comments