@@ -106,7 +106,15 @@ def __init__(
106106 # 6. Show semantic maps (v1.3 feature)
107107 self .show_semantic_maps = show_semantic_maps
108108
109- if not quiet :
109+ # 7. Communicate initialization (Love dimension)
110+ self ._communicate_startup ()
111+
112+ def _communicate_startup (self ):
113+ """
114+ Communicates startup information to user.
115+ Pure Love domain: clear, friendly communication.
116+ """
117+ if not self .quiet :
110118 print ("=" * 70 )
111119 print ("Python Code Harmonizer (v1.3) ONLINE" )
112120 print ("Actively guided by the Anchor Point framework." )
@@ -125,74 +133,103 @@ def analyze_file(self, file_path: str) -> Dict[str, Dict]:
125133 'semantic_map': Dict (from SemanticMapGenerator)
126134 }
127135 """
136+ # Love: Communicate what we're doing
137+ self ._communicate_analysis_start (file_path )
138+
139+ # Justice: Validate file exists and is readable
140+ content = self ._load_and_validate_file (file_path )
141+ if content is None :
142+ return {}
143+
144+ # Wisdom: Parse code into AST
145+ tree = self ._parse_code_to_ast (content , file_path )
146+ if tree is None :
147+ return {}
148+
149+ # Power: Execute analysis on all functions
150+ harmony_report = self ._analyze_all_functions (tree )
151+
152+ # Love: Communicate completion
153+ self ._communicate_analysis_complete (len (harmony_report ))
154+
155+ return harmony_report
156+
157+ def _communicate_analysis_start (self , file_path : str ):
158+ """Love dimension: Inform user analysis is starting."""
128159 if not self .quiet :
129160 print (f"\n Analyzing file: { file_path } " )
130161 print ("-" * 70 )
131162
163+ def _communicate_analysis_complete (self , function_count : int ):
164+ """Love dimension: Inform user analysis is complete."""
165+ if not self .quiet and function_count > 0 :
166+ print (f"✓ Analyzed { function_count } function(s)" )
167+
168+ def _load_and_validate_file (self , file_path : str ) -> str :
169+ """
170+ Justice dimension: Validate file and load content.
171+ Returns file content or None if validation fails.
172+ """
132173 try :
133174 with open (file_path , "r" , encoding = "utf-8" ) as f :
134- content = f .read ()
175+ return f .read ()
135176 except FileNotFoundError :
136177 if not self .quiet :
137178 print (f"ERROR: File not found at '{ file_path } '" )
138- return {}
179+ return None
139180 except Exception as e :
140181 if not self .quiet :
141182 print (f"ERROR: Could not read file: { e } " )
142- return {}
183+ return None
143184
144- # 1. Use Python's AST to parse the code into a logical tree
185+ def _parse_code_to_ast (self , content : str , file_path : str ) -> ast .AST :
186+ """
187+ Wisdom dimension: Parse Python code into Abstract Syntax Tree.
188+ Returns AST or None if parse fails.
189+ """
145190 try :
146- tree = ast .parse (content )
191+ return ast .parse (content )
147192 except SyntaxError as e :
148193 if not self .quiet :
149194 print (f"ERROR: Could not parse file. Syntax error on line { e .lineno } " )
150- return {}
195+ return None
151196
197+ def _analyze_all_functions (self , tree : ast .AST ) -> Dict [str , Dict ]:
198+ """
199+ Power dimension: Execute analysis on all functions in AST.
200+ Returns complete harmony report.
201+ """
152202 harmony_report = {}
153203
154- # 2. "Walk" the tree and visit every function definition
155204 for node in ast .walk (tree ):
156205 if isinstance (node , ast .FunctionDef ):
157206 function_name = node .name
158207 docstring = ast .get_docstring (node )
159208
160- # 3. Get INTENT: "The Stated Purpose"
161- # We use our parser to get the concepts from the name/docstring
209+ # Get intent and execution concepts
162210 intent_concepts = self .parser .get_intent_concepts (
163211 function_name , docstring
164212 )
165-
166- # 4. Get EXECUTION: "The Actual Action"
167- # We use our parser to get the concepts from the function's body
168213 execution_concepts = self .parser .get_execution_concepts (node .body )
169214
170- # 5. THE "A-HA!" MOMENT: Use the V2 ICEAnalyzer
171- # We pass our parsed concepts into the V2 engine's
172- # built-in ICE framework analyzer.
215+ # Perform ICE analysis
173216 ice_result = self .engine .perform_ice_analysis (
174217 intent_words = intent_concepts ,
175- context_words = [
176- "python" ,
177- "function" ,
178- function_name ,
179- ], # Provide context
218+ context_words = ["python" , "function" , function_name ],
180219 execution_words = execution_concepts ,
181220 )
182221
183- # The "bug" is the semantic distance between Intent and Execution
184- # This metric *is* returned by the "Optimized" V2 engine.
222+ # Calculate disharmony score
185223 disharmony_score = ice_result ["ice_metrics" ][
186224 "intent_execution_disharmony"
187225 ]
188226
189- # 6. Generate Semantic Map (v1.3)
190- # This shows WHERE in the 4D semantic space the disharmony occurs
227+ # Generate semantic map
191228 semantic_map = self .map_generator .generate_map (
192229 ice_result , function_name
193230 )
194231
195- # Store complete analysis data
232+ # Store complete analysis
196233 harmony_report [function_name ] = {
197234 "score" : disharmony_score ,
198235 "ice_result" : ice_result ,
@@ -240,15 +277,17 @@ def get_highest_severity_code(self, harmony_report: Dict[str, float]) -> int:
240277 else :
241278 return 0 # Excellent/Low
242279
243- def print_report (self , harmony_report : Dict [str , Dict ]):
244- """Prints the final harmony report to the console."""
245-
246- print ("FUNCTION NAME | INTENT-EXECUTION DISHARMONY" )
247- print ("-----------------------------|--------------------------------" )
248-
280+ def format_report (self , harmony_report : Dict [str , Dict ]) -> str :
281+ """
282+ Formats harmony report data into human-readable text.
283+ Pure Wisdom domain: analysis and formatting.
284+ """
249285 if not harmony_report :
250- print ("No functions found to analyze." )
251- return
286+ return "No functions found to analyze."
287+
288+ lines = []
289+ lines .append ("FUNCTION NAME | INTENT-EXECUTION DISHARMONY" )
290+ lines .append ("-----------------------------|--------------------------------" )
252291
253292 # Sort by score (now nested in the dict)
254293 sorted_report = sorted (
@@ -261,16 +300,24 @@ def print_report(self, harmony_report: Dict[str, Dict]):
261300 if score > self .disharmony_threshold :
262301 status = f"!! DISHARMONY (Score: { score :.2f} )"
263302
264- print (f"{ func_name :<28} | { status } " )
303+ lines . append (f"{ func_name :<28} | { status } " )
265304
266305 # Show semantic map for disharmonious functions (v1.3)
267306 if self .show_semantic_maps and score > self .disharmony_threshold :
268307 semantic_map = data ["semantic_map" ]
269308 map_text = self .map_generator .format_text_map (semantic_map , score )
270- print (map_text )
309+ lines . append (map_text )
271310
272- print ("=" * 70 )
273- print ("Analysis Complete." )
311+ lines .append ("=" * 70 )
312+ lines .append ("Analysis Complete." )
313+ return "\n " .join (lines )
314+
315+ def output_report (self , formatted_report : str ):
316+ """
317+ Outputs formatted report to console.
318+ Pure Love domain: communication and display.
319+ """
320+ print (formatted_report )
274321
275322 def print_json_report (self , all_reports : Dict [str , Dict [str , Dict ]]):
276323 """Prints the harmony report in JSON format."""
@@ -342,8 +389,11 @@ def _get_highest_severity_name(self, severity_counts: Dict[str, int]) -> str:
342389# --- MAIN EXECUTION ---
343390
344391
345- def run_cli ():
346- """Command-line interface entry point."""
392+ def parse_cli_arguments () -> argparse .Namespace :
393+ """
394+ Parses command-line arguments.
395+ Pure Wisdom domain: understanding user intent.
396+ """
347397 parser = argparse .ArgumentParser (
348398 description = "Python Code Harmonizer - Semantic code analysis tool" ,
349399 formatter_class = argparse .RawDescriptionHelpFormatter ,
@@ -387,41 +437,94 @@ def run_cli():
387437 parser .add_argument (
388438 "--version" ,
389439 action = "version" ,
390- version = "Python Code Harmonizer v1.2 " ,
440+ version = "Python Code Harmonizer v1.3 " ,
391441 )
392442
393- args = parser .parse_args ()
443+ return parser .parse_args ()
394444
395- # 1. Initialize the Harmonizer
396- quiet = args .format == "json"
397- harmonizer = PythonCodeHarmonizer (disharmony_threshold = args .threshold , quiet = quiet )
398445
399- # 2. Run the analysis for all provided files
400- all_reports = {}
401- highest_exit_code = 0
446+ def validate_cli_arguments (args : argparse .Namespace ) -> List [str ]:
447+ """
448+ Validates command-line arguments.
449+ Pure Justice domain: verification and error checking.
450+ Returns list of valid file paths.
451+ """
452+ valid_files = []
453+ invalid_files = []
402454
403455 for file_path in args .files :
404456 if os .path .exists (file_path ):
405- report = harmonizer .analyze_file (file_path )
406- all_reports [file_path ] = report
457+ if file_path .endswith (".py" ):
458+ valid_files .append (file_path )
459+ else :
460+ invalid_files .append ((file_path , "Not a Python file" ))
461+ else :
462+ invalid_files .append ((file_path , "File not found" ))
407463
408- # Track highest severity for exit code
409- exit_code = harmonizer .get_highest_severity_code (report )
410- highest_exit_code = max (highest_exit_code , exit_code )
464+ # Report validation errors (Love dimension: communication)
465+ if invalid_files and args .format == "text" :
466+ for file_path , error in invalid_files :
467+ print (f"\n WARNING: { file_path } - { error } " )
468+ print ("-" * 70 )
411469
412- # Print text report immediately if not JSON
413- if args .format == "text" :
414- harmonizer .print_report (report )
415- else :
416- if args .format == "text" :
417- print (f"\n ERROR: File not found: { file_path } " )
418- print ("-" * 70 )
470+ return valid_files
471+
472+
473+ def execute_analysis (
474+ harmonizer : PythonCodeHarmonizer , file_paths : List [str ], output_format : str
475+ ) -> tuple [Dict [str , Dict [str , Dict ]], int ]:
476+ """
477+ Executes the analysis pipeline.
478+ Pure Power domain: orchestrating the actual work.
479+ Returns (all_reports, highest_exit_code).
480+ """
481+ all_reports = {}
482+ highest_exit_code = 0
483+
484+ for file_path in file_paths :
485+ report = harmonizer .analyze_file (file_path )
486+ all_reports [file_path ] = report
487+
488+ # Track highest severity for exit code
489+ exit_code = harmonizer .get_highest_severity_code (report )
490+ highest_exit_code = max (highest_exit_code , exit_code )
491+
492+ # Print text report immediately if not JSON
493+ if output_format == "text" :
494+ formatted = harmonizer .format_report (report )
495+ harmonizer .output_report (formatted )
496+
497+ return all_reports , highest_exit_code
498+
499+
500+ def run_cli ():
501+ """
502+ Command-line interface entry point.
503+ Orchestrates all dimensions: Wisdom → Justice → Power → Love.
504+ """
505+ # 1. Wisdom: Parse and understand arguments
506+ args = parse_cli_arguments ()
507+
508+ # 2. Justice: Validate arguments
509+ valid_files = validate_cli_arguments (args )
510+
511+ if not valid_files :
512+ print ("\n ERROR: No valid Python files to analyze." )
513+ sys .exit (1 )
514+
515+ # 3. Power: Initialize harmonizer and execute analysis
516+ quiet = args .format == "json"
517+ harmonizer = PythonCodeHarmonizer (disharmony_threshold = args .threshold , quiet = quiet )
518+
519+ all_reports , highest_exit_code = execute_analysis (
520+ harmonizer , valid_files , args .format
521+ )
419522
420- # 3. Print JSON report if requested
523+ # 4. Love: Communicate final results if JSON format
421524 if args .format == "json" :
422525 harmonizer .print_json_report (all_reports )
423526
424- # 4. Exit with appropriate code for CI/CD
527+ # 5. Return status code for CI/CD integration
425528 sys .exit (highest_exit_code )
426529
427530
0 commit comments