code2llm 0.3.10__tar.gz → 0.3.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {code2llm-0.3.10 → code2llm-0.3.11}/PKG-INFO +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/__init__.py +2 -2
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/__main__.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/__init__.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/data_analysis.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/pipeline_detector.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/cli.py +18 -27
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/core/__init__.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/core/analyzer.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/core/config.py +2 -2
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/core/streaming_analyzer.py +2 -2
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/__init__.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/base.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/context_exporter.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/json_exporter.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/mermaid_exporter.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/toon.py +2 -2
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/yaml_exporter.py +1 -1
- code2llm-0.3.11/code2llm/generators/__init__.py +12 -0
- code2llm-0.3.10/code2flow/llm_flow_generator.py → code2llm-0.3.11/code2llm/generators/llm_flow.py +1 -1
- code2llm-0.3.10/code2flow/mermaid_generator.py → code2llm-0.3.11/code2llm/generators/mermaid.py +1 -1
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/nlp/__init__.py +1 -1
- {code2llm-0.3.10 → code2llm-0.3.11}/code2llm.egg-info/PKG-INFO +1 -1
- code2llm-0.3.11/code2llm.egg-info/SOURCES.txt +63 -0
- code2llm-0.3.11/code2llm.egg-info/entry_points.txt +2 -0
- code2llm-0.3.11/code2llm.egg-info/top_level.txt +1 -0
- {code2llm-0.3.10 → code2llm-0.3.11}/pyproject.toml +3 -3
- {code2llm-0.3.10 → code2llm-0.3.11}/setup.py +1 -1
- {code2llm-0.3.10 → code2llm-0.3.11}/tests/test_advanced_analysis.py +6 -6
- {code2llm-0.3.10 → code2llm-0.3.11}/tests/test_analyzer.py +6 -6
- code2llm-0.3.10/tests/test_sprint4.py → code2llm-0.3.11/tests/test_deep_analysis.py +3 -3
- {code2llm-0.3.10 → code2llm-0.3.11}/tests/test_edge_cases.py +5 -5
- code2llm-0.3.10/tests/test_sprint2_flow.py → code2llm-0.3.11/tests/test_flow_exporter.py +4 -4
- {code2llm-0.3.10 → code2llm-0.3.11}/tests/test_format_quality.py +11 -11
- {code2llm-0.3.10 → code2llm-0.3.11}/tests/test_nlp_pipeline.py +10 -10
- code2llm-0.3.10/tests/test_sprint3_pipelines.py → code2llm-0.3.11/tests/test_pipeline_detector.py +8 -8
- code2llm-0.3.10/tests/test_sprint5.py → code2llm-0.3.11/tests/test_prompt_engine.py +2 -2
- {code2llm-0.3.10 → code2llm-0.3.11}/tests/test_refactoring_engine.py +7 -7
- {code2llm-0.3.10 → code2llm-0.3.11}/tests/test_toon_v2.py +6 -6
- code2llm-0.3.10/code2flow/visualizers/__init__.py +0 -0
- code2llm-0.3.10/code2flow/visualizers/graph.py +0 -196
- code2llm-0.3.10/code2llm.egg-info/SOURCES.txt +0 -64
- code2llm-0.3.10/code2llm.egg-info/entry_points.txt +0 -2
- code2llm-0.3.10/code2llm.egg-info/top_level.txt +0 -1
- {code2llm-0.3.10 → code2llm-0.3.11}/LICENSE +0 -0
- {code2llm-0.3.10 → code2llm-0.3.11}/README.md +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/call_graph.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/cfg.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/coupling.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/dfg.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/side_effects.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/smells.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/analysis/type_inference.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/core/models.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/flow_exporter.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/llm_exporter.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/exporters/map_exporter.py +0 -0
- /code2llm-0.3.10/code2flow/llm_task_generator.py → /code2llm-0.3.11/code2llm/generators/llm_task.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/nlp/config.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/nlp/entity_resolution.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/nlp/intent_matching.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/nlp/normalization.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/nlp/pipeline.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/patterns/__init__.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/patterns/detector.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/refactor/__init__.py +0 -0
- {code2llm-0.3.10/code2flow → code2llm-0.3.11/code2llm}/refactor/prompt_engine.py +0 -0
- {code2llm-0.3.10 → code2llm-0.3.11}/code2llm.egg-info/dependency_links.txt +0 -0
- {code2llm-0.3.10 → code2llm-0.3.11}/code2llm.egg-info/requires.txt +0 -0
- {code2llm-0.3.10 → code2llm-0.3.11}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2llm
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: High-performance Python code flow analysis with optimized TOON format - CFG, DFG, call graphs, and intelligent code queries
|
|
5
5
|
Home-page: https://github.com/wronai/stts
|
|
6
6
|
Author: STTS Project
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
code2llm - Optimized Python Code Flow Analysis Tool
|
|
3
3
|
|
|
4
4
|
A high-performance tool for analyzing Python code control flow, data flow,
|
|
5
5
|
and call graphs with caching and parallel processing.
|
|
@@ -8,7 +8,7 @@ Includes NLP Processing Pipeline for query normalization, intent matching,
|
|
|
8
8
|
and entity resolution with multilingual support.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
__version__ = "0.3.
|
|
11
|
+
__version__ = "0.3.3"
|
|
12
12
|
__author__ = "STTS Project"
|
|
13
13
|
|
|
14
14
|
# Core analysis components
|
|
@@ -395,7 +395,7 @@ class PipelineDetector:
|
|
|
395
395
|
parts = fi.module.split(".")
|
|
396
396
|
# Use most specific module component
|
|
397
397
|
for part in parts:
|
|
398
|
-
if part and part not in ("
|
|
398
|
+
if part and part not in ("code2llm", "__init__"):
|
|
399
399
|
module_counts[part] += 1
|
|
400
400
|
|
|
401
401
|
if module_counts:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
|
-
|
|
3
|
+
code2llm - CLI for Python code flow analysis
|
|
4
4
|
|
|
5
5
|
Analyze control flow, data flow, and call graphs of Python codebases.
|
|
6
6
|
"""
|
|
@@ -16,23 +16,23 @@ from .exporters import (
|
|
|
16
16
|
ContextExporter, LLMPromptExporter,
|
|
17
17
|
ToonExporter, MapExporter, FlowExporter,
|
|
18
18
|
)
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def create_parser() -> argparse.ArgumentParser:
|
|
23
23
|
"""Create CLI argument parser."""
|
|
24
24
|
parser = argparse.ArgumentParser(
|
|
25
|
-
prog='
|
|
25
|
+
prog='code2llm',
|
|
26
26
|
description='Analyze Python code control flow, data flow, and call graphs',
|
|
27
27
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
28
28
|
epilog='''
|
|
29
29
|
Examples:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
code2llm /path/to/project # Default: TOON format only
|
|
31
|
+
code2llm /path/to/project -f all # Generate all formats
|
|
32
|
+
code2llm /path/to/project -f toon,map,flow # Diagnostics + structure + data-flow
|
|
33
|
+
code2llm /path/to/project -f context # LLM narrative context
|
|
34
|
+
code2llm /path/to/project -m static -o ./analysis
|
|
35
|
+
code2llm llm-flow # Generate LLM flow summary
|
|
36
36
|
|
|
37
37
|
Format Options:
|
|
38
38
|
toon - Health diagnostics (analysis.toon) — default
|
|
@@ -42,7 +42,6 @@ Format Options:
|
|
|
42
42
|
yaml - Standard YAML format
|
|
43
43
|
json - Machine-readable JSON
|
|
44
44
|
mermaid - Flowchart diagrams
|
|
45
|
-
png - Visual graphs
|
|
46
45
|
all - Generate all formats
|
|
47
46
|
'''
|
|
48
47
|
)
|
|
@@ -63,8 +62,8 @@ Format Options:
|
|
|
63
62
|
|
|
64
63
|
parser.add_argument(
|
|
65
64
|
'-o', '--output',
|
|
66
|
-
default='./
|
|
67
|
-
help='Output directory (default: ./
|
|
65
|
+
default='./code2llm_output',
|
|
66
|
+
help='Output directory (default: ./code2llm_output)'
|
|
68
67
|
)
|
|
69
68
|
|
|
70
69
|
parser.add_argument(
|
|
@@ -179,7 +178,7 @@ def main():
|
|
|
179
178
|
"""Main CLI entry point."""
|
|
180
179
|
# Handle special cases first
|
|
181
180
|
if len(sys.argv) > 1 and sys.argv[1] == 'llm-flow':
|
|
182
|
-
from .
|
|
181
|
+
from .generators.llm_flow import main as llm_flow_main
|
|
183
182
|
return llm_flow_main(sys.argv[2:])
|
|
184
183
|
|
|
185
184
|
if len(sys.argv) > 1 and sys.argv[1] == 'llm-context':
|
|
@@ -193,8 +192,8 @@ def main():
|
|
|
193
192
|
# Handle analysis (default behavior)
|
|
194
193
|
if not args.source:
|
|
195
194
|
print("Error: missing required argument: source", file=sys.stderr)
|
|
196
|
-
print("Usage:
|
|
197
|
-
print(" or:
|
|
195
|
+
print("Usage: code2llm <source> [options]", file=sys.stderr)
|
|
196
|
+
print(" or: code2llm llm-flow [options]", file=sys.stderr)
|
|
198
197
|
sys.exit(2)
|
|
199
198
|
|
|
200
199
|
# Validate source path
|
|
@@ -293,7 +292,7 @@ def main():
|
|
|
293
292
|
|
|
294
293
|
# Handle 'all' format
|
|
295
294
|
if 'all' in formats:
|
|
296
|
-
formats = ['toon', 'map', 'flow', 'context', 'yaml', 'json', 'mermaid'
|
|
295
|
+
formats = ['toon', 'map', 'flow', 'context', 'yaml', 'json', 'mermaid']
|
|
297
296
|
|
|
298
297
|
try:
|
|
299
298
|
if 'toon' in formats:
|
|
@@ -365,7 +364,7 @@ def main():
|
|
|
365
364
|
# Auto-generate PNG from Mermaid files (unless disabled)
|
|
366
365
|
if not args.no_png:
|
|
367
366
|
try:
|
|
368
|
-
from .
|
|
367
|
+
from .generators.mermaid import generate_pngs
|
|
369
368
|
png_count = generate_pngs(output_dir, output_dir)
|
|
370
369
|
if args.verbose and png_count > 0:
|
|
371
370
|
print(f" - PNG: {png_count} files generated")
|
|
@@ -387,15 +386,7 @@ def main():
|
|
|
387
386
|
elif args.verbose:
|
|
388
387
|
print(f" - PNG: Skipped (--no-png)")
|
|
389
388
|
|
|
390
|
-
|
|
391
|
-
visualizer = GraphVisualizer(result)
|
|
392
|
-
filepath = output_dir / 'cfg.png'
|
|
393
|
-
visualizer.visualize_cfg(str(filepath))
|
|
394
|
-
filepath = output_dir / 'call_graph.png'
|
|
395
|
-
visualizer.visualize_call_graph(str(filepath))
|
|
396
|
-
if args.verbose:
|
|
397
|
-
print(f" - PNG: {output_dir / '*.png'}")
|
|
398
|
-
|
|
389
|
+
|
|
399
390
|
if args.data_structures:
|
|
400
391
|
exporter = YAMLExporter()
|
|
401
392
|
struct_path = output_dir / 'data_structures.yaml'
|
|
@@ -450,7 +441,7 @@ def generate_llm_context(args_list):
|
|
|
450
441
|
import argparse
|
|
451
442
|
|
|
452
443
|
parser = argparse.ArgumentParser(
|
|
453
|
-
prog='
|
|
444
|
+
prog='code2llm llm-context',
|
|
454
445
|
description='Generate LLM-friendly context for a project'
|
|
455
446
|
)
|
|
456
447
|
parser.add_argument('source', help='Path to Python project')
|
|
@@ -29,7 +29,7 @@ from ..analysis.smells import SmellDetector
|
|
|
29
29
|
class FileCache:
|
|
30
30
|
"""Cache for parsed AST files."""
|
|
31
31
|
|
|
32
|
-
def __init__(self, cache_dir: str = ".
|
|
32
|
+
def __init__(self, cache_dir: str = ".code2llm_cache", ttl_hours: int = 24):
|
|
33
33
|
self.cache_dir = Path(cache_dir)
|
|
34
34
|
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
|
35
35
|
self.ttl_seconds = ttl_hours * 3600
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Configuration and constants for
|
|
1
|
+
"""Configuration and constants for code2llm."""
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from typing import List, Set
|
|
@@ -18,7 +18,7 @@ class AnalysisMode(str, Enum):
|
|
|
18
18
|
class PerformanceConfig:
|
|
19
19
|
"""Performance optimization settings."""
|
|
20
20
|
enable_cache: bool = True
|
|
21
|
-
cache_dir: str = ".
|
|
21
|
+
cache_dir: str = ".code2llm_cache"
|
|
22
22
|
cache_ttl_hours: int = 24
|
|
23
23
|
parallel_workers: int = 4
|
|
24
24
|
parallel_enabled: bool = True
|
|
@@ -110,7 +110,7 @@ STRATEGY_DEEP = ScanStrategy(
|
|
|
110
110
|
class StreamingFileCache:
|
|
111
111
|
"""Memory-efficient cache with LRU eviction."""
|
|
112
112
|
|
|
113
|
-
def __init__(self, max_size: int = 100, cache_dir: str = ".
|
|
113
|
+
def __init__(self, max_size: int = 100, cache_dir: str = ".code2llm_cache"):
|
|
114
114
|
self.max_size = max_size
|
|
115
115
|
self.cache_dir = Path(cache_dir)
|
|
116
116
|
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -605,7 +605,7 @@ class IncrementalAnalyzer:
|
|
|
605
605
|
|
|
606
606
|
def __init__(self, config: Optional[Config] = None):
|
|
607
607
|
self.config = config or FAST_CONFIG
|
|
608
|
-
self.state_file = Path(".
|
|
608
|
+
self.state_file = Path(".code2llm_state.json")
|
|
609
609
|
self.previous_state: Dict[str, str] = {}
|
|
610
610
|
self._load_state()
|
|
611
611
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Context Exporter for
|
|
1
|
+
"""Context Exporter for code2llm — generates context.md (LLM narrative).
|
|
2
2
|
|
|
3
3
|
Rename from llm_exporter.py → context_exporter.py (Sprint 4, v0.3.3).
|
|
4
4
|
Produces LLM-ready architecture summary with flows, patterns, and API surface.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Toon Exporter v2 — scannable plain-text format for
|
|
1
|
+
"""Toon Exporter v2 — scannable plain-text format for code2llm.
|
|
2
2
|
|
|
3
3
|
Structure communicates health: sorting by severity, inline markers,
|
|
4
4
|
coupling matrix, duplicate detection, filtered functions.
|
|
@@ -490,7 +490,7 @@ class ToonExporter:
|
|
|
490
490
|
ncycles = len(ctx["cycles"])
|
|
491
491
|
|
|
492
492
|
lines = [
|
|
493
|
-
f"#
|
|
493
|
+
f"# code2llm | {nfiles}f {total_lines}L | py:{nfiles} | {ctx['timestamp']}",
|
|
494
494
|
f"# CC\u0304={avg_cc} | critical:{critical}/{nfuncs} | dups:{ndups} | cycles:{ncycles}",
|
|
495
495
|
]
|
|
496
496
|
return lines
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""code2llm generators package.
|
|
2
|
+
|
|
3
|
+
Generators for LLM flow summaries, task breakdowns, and Mermaid diagrams.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .llm_flow import main as llm_flow_main
|
|
7
|
+
from .mermaid import generate_pngs
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
'llm_flow_main',
|
|
11
|
+
'generate_pngs',
|
|
12
|
+
]
|
code2llm-0.3.10/code2flow/llm_flow_generator.py → code2llm-0.3.11/code2llm/generators/llm_flow.py
RENAMED
|
@@ -394,7 +394,7 @@ def dump_yaml(data: Dict[str, Any]) -> str:
|
|
|
394
394
|
def create_parser() -> argparse.ArgumentParser:
|
|
395
395
|
p = argparse.ArgumentParser(
|
|
396
396
|
prog="llm-flow-generator",
|
|
397
|
-
description="Generate compact LLM-friendly app flow summary from
|
|
397
|
+
description="Generate compact LLM-friendly app flow summary from code2llm analysis.yaml",
|
|
398
398
|
)
|
|
399
399
|
p.add_argument(
|
|
400
400
|
"-i",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2llm
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: High-performance Python code flow analysis with optimized TOON format - CFG, DFG, call graphs, and intelligent code queries
|
|
5
5
|
Home-page: https://github.com/wronai/stts
|
|
6
6
|
Author: STTS Project
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
code2llm/__init__.py
|
|
6
|
+
code2llm/__main__.py
|
|
7
|
+
code2llm/cli.py
|
|
8
|
+
code2llm.egg-info/PKG-INFO
|
|
9
|
+
code2llm.egg-info/SOURCES.txt
|
|
10
|
+
code2llm.egg-info/dependency_links.txt
|
|
11
|
+
code2llm.egg-info/entry_points.txt
|
|
12
|
+
code2llm.egg-info/requires.txt
|
|
13
|
+
code2llm.egg-info/top_level.txt
|
|
14
|
+
code2llm/analysis/__init__.py
|
|
15
|
+
code2llm/analysis/call_graph.py
|
|
16
|
+
code2llm/analysis/cfg.py
|
|
17
|
+
code2llm/analysis/coupling.py
|
|
18
|
+
code2llm/analysis/data_analysis.py
|
|
19
|
+
code2llm/analysis/dfg.py
|
|
20
|
+
code2llm/analysis/pipeline_detector.py
|
|
21
|
+
code2llm/analysis/side_effects.py
|
|
22
|
+
code2llm/analysis/smells.py
|
|
23
|
+
code2llm/analysis/type_inference.py
|
|
24
|
+
code2llm/core/__init__.py
|
|
25
|
+
code2llm/core/analyzer.py
|
|
26
|
+
code2llm/core/config.py
|
|
27
|
+
code2llm/core/models.py
|
|
28
|
+
code2llm/core/streaming_analyzer.py
|
|
29
|
+
code2llm/exporters/__init__.py
|
|
30
|
+
code2llm/exporters/base.py
|
|
31
|
+
code2llm/exporters/context_exporter.py
|
|
32
|
+
code2llm/exporters/flow_exporter.py
|
|
33
|
+
code2llm/exporters/json_exporter.py
|
|
34
|
+
code2llm/exporters/llm_exporter.py
|
|
35
|
+
code2llm/exporters/map_exporter.py
|
|
36
|
+
code2llm/exporters/mermaid_exporter.py
|
|
37
|
+
code2llm/exporters/toon.py
|
|
38
|
+
code2llm/exporters/yaml_exporter.py
|
|
39
|
+
code2llm/generators/__init__.py
|
|
40
|
+
code2llm/generators/llm_flow.py
|
|
41
|
+
code2llm/generators/llm_task.py
|
|
42
|
+
code2llm/generators/mermaid.py
|
|
43
|
+
code2llm/nlp/__init__.py
|
|
44
|
+
code2llm/nlp/config.py
|
|
45
|
+
code2llm/nlp/entity_resolution.py
|
|
46
|
+
code2llm/nlp/intent_matching.py
|
|
47
|
+
code2llm/nlp/normalization.py
|
|
48
|
+
code2llm/nlp/pipeline.py
|
|
49
|
+
code2llm/patterns/__init__.py
|
|
50
|
+
code2llm/patterns/detector.py
|
|
51
|
+
code2llm/refactor/__init__.py
|
|
52
|
+
code2llm/refactor/prompt_engine.py
|
|
53
|
+
tests/test_advanced_analysis.py
|
|
54
|
+
tests/test_analyzer.py
|
|
55
|
+
tests/test_deep_analysis.py
|
|
56
|
+
tests/test_edge_cases.py
|
|
57
|
+
tests/test_flow_exporter.py
|
|
58
|
+
tests/test_format_quality.py
|
|
59
|
+
tests/test_nlp_pipeline.py
|
|
60
|
+
tests/test_pipeline_detector.py
|
|
61
|
+
tests/test_prompt_engine.py
|
|
62
|
+
tests/test_refactoring_engine.py
|
|
63
|
+
tests/test_toon_v2.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
code2llm
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code2llm"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.11"
|
|
8
8
|
description = "High-performance Python code flow analysis with optimized TOON format - CFG, DFG, call graphs, and intelligent code queries"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -62,7 +62,7 @@ dev = [
|
|
|
62
62
|
]
|
|
63
63
|
|
|
64
64
|
[project.scripts]
|
|
65
|
-
|
|
65
|
+
code2llm = "code2llm.cli:main"
|
|
66
66
|
|
|
67
67
|
[project.urls]
|
|
68
68
|
Homepage = "https://github.com/wronai/stts"
|
|
@@ -74,7 +74,7 @@ line-length = 100
|
|
|
74
74
|
target-version = ['py38']
|
|
75
75
|
|
|
76
76
|
[tool.mypy]
|
|
77
|
-
python_version = "0.3.
|
|
77
|
+
python_version = "0.3.11"
|
|
78
78
|
ignore_missing_imports = true
|
|
79
79
|
|
|
80
80
|
[tool.pytest.ini_options]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
import ast
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
3
|
+
from code2llm.core.analyzer import ProjectAnalyzer
|
|
4
|
+
from code2llm.core.config import Config
|
|
5
|
+
from code2llm.core.models import AnalysisResult
|
|
6
6
|
|
|
7
7
|
def test_radon_complexity():
|
|
8
8
|
content = """
|
|
@@ -20,7 +20,7 @@ def complex_func(x):
|
|
|
20
20
|
print(i)
|
|
21
21
|
return 0
|
|
22
22
|
"""
|
|
23
|
-
from
|
|
23
|
+
from code2llm.core.analyzer import FileAnalyzer
|
|
24
24
|
config = Config()
|
|
25
25
|
config.verbose = True
|
|
26
26
|
analyzer = FileAnalyzer(config)
|
|
@@ -49,7 +49,7 @@ def test_graph_metrics():
|
|
|
49
49
|
# Actually Betweenness Centrality on:
|
|
50
50
|
# A -> B, B -> C, A -> D, D -> C
|
|
51
51
|
|
|
52
|
-
from
|
|
52
|
+
from code2llm.core.models import FunctionInfo
|
|
53
53
|
|
|
54
54
|
func_names = ["A", "B", "C", "D"]
|
|
55
55
|
for name in func_names:
|
|
@@ -73,7 +73,7 @@ def test_graph_metrics():
|
|
|
73
73
|
|
|
74
74
|
def test_circular_dependency():
|
|
75
75
|
result = AnalysisResult()
|
|
76
|
-
from
|
|
76
|
+
from code2llm.core.models import FunctionInfo
|
|
77
77
|
|
|
78
78
|
# A -> B -> A
|
|
79
79
|
result.functions["A"] = FunctionInfo(name="A", qualified_name="A", file="test.py", line=1)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
"""Test suite for
|
|
1
|
+
"""Test suite for code2llm."""
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
import tempfile
|
|
5
5
|
import shutil
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from
|
|
8
|
-
from
|
|
7
|
+
from code2llm import ProjectAnalyzer, Config
|
|
8
|
+
from code2llm.core.config import FAST_CONFIG, FilterConfig
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class TestProjectAnalyzer:
|
|
@@ -175,7 +175,7 @@ class TestExporters:
|
|
|
175
175
|
@pytest.fixture
|
|
176
176
|
def sample_result(self):
|
|
177
177
|
"""Create sample analysis result."""
|
|
178
|
-
from
|
|
178
|
+
from code2llm.core.models import AnalysisResult, FunctionInfo
|
|
179
179
|
|
|
180
180
|
result = AnalysisResult(
|
|
181
181
|
project_path="/test",
|
|
@@ -199,7 +199,7 @@ class TestExporters:
|
|
|
199
199
|
|
|
200
200
|
def test_json_export(self, sample_result, tmp_path):
|
|
201
201
|
"""Test JSON export."""
|
|
202
|
-
from
|
|
202
|
+
from code2llm.exporters.base import JSONExporter
|
|
203
203
|
|
|
204
204
|
output = tmp_path / "output.json"
|
|
205
205
|
exporter = JSONExporter()
|
|
@@ -212,7 +212,7 @@ class TestExporters:
|
|
|
212
212
|
|
|
213
213
|
def test_mermaid_export(self, sample_result, tmp_path):
|
|
214
214
|
"""Test Mermaid export."""
|
|
215
|
-
from
|
|
215
|
+
from code2llm.exporters.base import MermaidExporter
|
|
216
216
|
|
|
217
217
|
output = tmp_path / "output.mmd"
|
|
218
218
|
exporter = MermaidExporter()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
import os
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
4
|
+
from code2llm.core.analyzer import ProjectAnalyzer, FileAnalyzer
|
|
5
|
+
from code2llm.core.config import Config
|
|
6
|
+
from code2llm.core.models import AnalysisResult
|
|
7
7
|
|
|
8
8
|
def test_astroid_resolution_mock(tmp_path):
|
|
9
9
|
# Create two files. A.py calls B.func() via an instance.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
"""Additional tests for
|
|
1
|
+
"""Additional tests for code2llm - edge cases and integration tests."""
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
import tempfile
|
|
5
5
|
import shutil
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from
|
|
7
|
+
from code2llm import ProjectAnalyzer, FAST_CONFIG, NLPPipeline, FAST_NLP_CONFIG, Config
|
|
8
|
+
from code2llm.core.analyzer import FileCache, FastFileFilter
|
|
9
|
+
from code2llm.core.config import FilterConfig, PerformanceConfig
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class TestEdgeCases:
|
|
@@ -305,7 +305,7 @@ def standalone_func(): pass
|
|
|
305
305
|
analysis = analyzer.analyze_project(str(tmp_dir))
|
|
306
306
|
|
|
307
307
|
# Load entities
|
|
308
|
-
from
|
|
308
|
+
from code2llm.nlp import EntityResolver
|
|
309
309
|
resolver = EntityResolver()
|
|
310
310
|
resolver.load_from_analysis(analysis)
|
|
311
311
|
|
|
@@ -12,10 +12,10 @@ import tempfile
|
|
|
12
12
|
import pytest
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
|
|
15
|
-
from
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from
|
|
15
|
+
from code2llm.core.models import AnalysisResult, FunctionInfo, ModuleInfo
|
|
16
|
+
from code2llm.analysis.type_inference import TypeInferenceEngine
|
|
17
|
+
from code2llm.analysis.side_effects import SideEffectDetector, SideEffectInfo
|
|
18
|
+
from code2llm.exporters.flow_exporter import FlowExporter
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
# ---------------------------------------------------------------------------
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Pytest-based format quality tests.
|
|
4
4
|
|
|
5
|
-
These verify that each
|
|
5
|
+
These verify that each code2llm output format correctly detects
|
|
6
6
|
known problems in a controlled test project.
|
|
7
7
|
|
|
8
8
|
Run with: pytest tests/test_format_quality.py -v
|
|
@@ -143,8 +143,8 @@ def ground_truth_project(tmp_path_factory) -> Path:
|
|
|
143
143
|
|
|
144
144
|
@pytest.fixture(scope="module")
|
|
145
145
|
def analysis_result(ground_truth_project):
|
|
146
|
-
"""Run
|
|
147
|
-
from
|
|
146
|
+
"""Run code2llm analysis on ground truth project."""
|
|
147
|
+
from code2llm import ProjectAnalyzer, Config
|
|
148
148
|
cfg = Config()
|
|
149
149
|
cfg.filters.exclude_patterns = [
|
|
150
150
|
'*__pycache__*', '*.pyc', '*venv*', '*.venv*',
|
|
@@ -165,7 +165,7 @@ class TestAnalysisToon:
|
|
|
165
165
|
|
|
166
166
|
@pytest.fixture
|
|
167
167
|
def toon_content(self, analysis_result, tmp_path):
|
|
168
|
-
from
|
|
168
|
+
from code2llm.exporters.toon import ToonExporter
|
|
169
169
|
out = tmp_path / "analysis.toon"
|
|
170
170
|
ToonExporter().export(analysis_result, str(out))
|
|
171
171
|
return out.read_text()
|
|
@@ -206,7 +206,7 @@ class TestFlowToon:
|
|
|
206
206
|
|
|
207
207
|
@pytest.fixture
|
|
208
208
|
def flow_content(self, analysis_result, tmp_path):
|
|
209
|
-
from
|
|
209
|
+
from code2llm.exporters.flow_exporter import FlowExporter
|
|
210
210
|
out = tmp_path / "flow.toon"
|
|
211
211
|
FlowExporter().export(analysis_result, str(out))
|
|
212
212
|
return out.read_text()
|
|
@@ -246,7 +246,7 @@ class TestProjectMap:
|
|
|
246
246
|
|
|
247
247
|
@pytest.fixture
|
|
248
248
|
def map_content(self, analysis_result, tmp_path):
|
|
249
|
-
from
|
|
249
|
+
from code2llm.exporters.map_exporter import MapExporter
|
|
250
250
|
out = tmp_path / "project.map"
|
|
251
251
|
MapExporter().export(analysis_result, str(out))
|
|
252
252
|
return out.read_text()
|
|
@@ -279,7 +279,7 @@ class TestContextMd:
|
|
|
279
279
|
|
|
280
280
|
@pytest.fixture
|
|
281
281
|
def context_content(self, analysis_result, tmp_path):
|
|
282
|
-
from
|
|
282
|
+
from code2llm.exporters.llm_exporter import LLMPromptExporter
|
|
283
283
|
out = tmp_path / "context.md"
|
|
284
284
|
LLMPromptExporter().export(analysis_result, str(out))
|
|
285
285
|
return out.read_text()
|
|
@@ -305,10 +305,10 @@ class TestCrossFormat:
|
|
|
305
305
|
def all_formats(self, analysis_result, tmp_path):
|
|
306
306
|
formats = {}
|
|
307
307
|
exporters = {
|
|
308
|
-
"analysis.toon": ("
|
|
309
|
-
"flow.toon": ("
|
|
310
|
-
"project.map": ("
|
|
311
|
-
"context.md": ("
|
|
308
|
+
"analysis.toon": ("code2llm.exporters.toon", "ToonExporter"),
|
|
309
|
+
"flow.toon": ("code2llm.exporters.flow_exporter", "FlowExporter"),
|
|
310
|
+
"project.map": ("code2llm.exporters.map_exporter", "MapExporter"),
|
|
311
|
+
"context.md": ("code2llm.exporters.llm_exporter", "LLMPromptExporter"),
|
|
312
312
|
}
|
|
313
313
|
for name, (mod_path, cls_name) in exporters.items():
|
|
314
314
|
try:
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"""Tests for NLP Processing Pipeline."""
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
|
-
from
|
|
4
|
+
from code2llm.nlp import (
|
|
5
5
|
NLPPipeline, QueryNormalizer, IntentMatcher, EntityResolver,
|
|
6
6
|
NLPConfig, FAST_NLP_CONFIG, PRECISE_NLP_CONFIG
|
|
7
7
|
)
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from
|
|
8
|
+
from code2llm.nlp.normalization import NormalizationResult
|
|
9
|
+
from code2llm.nlp.intent_matching import IntentMatchingResult, IntentMatch
|
|
10
|
+
from code2llm.nlp.entity_resolution import EntityResolutionResult, Entity
|
|
11
|
+
from code2llm.nlp.config import EntityResolutionConfig
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class TestQueryNormalization:
|
|
@@ -48,7 +48,7 @@ class TestQueryNormalization:
|
|
|
48
48
|
|
|
49
49
|
def test_step_1e_remove_stopwords(self):
|
|
50
50
|
"""1e. Stopword removal."""
|
|
51
|
-
from
|
|
51
|
+
from code2llm.nlp.config import NormalizationConfig
|
|
52
52
|
|
|
53
53
|
config = NormalizationConfig(remove_stopwords=True)
|
|
54
54
|
normalizer = QueryNormalizer(config)
|
|
@@ -103,7 +103,7 @@ class TestIntentMatching:
|
|
|
103
103
|
|
|
104
104
|
def test_step_2e_multi_intent_resolution(self):
|
|
105
105
|
"""2e. Multi-intent resolution strategy."""
|
|
106
|
-
from
|
|
106
|
+
from code2llm.nlp.config import IntentMatchingConfig
|
|
107
107
|
|
|
108
108
|
config = IntentMatchingConfig(multi_intent_strategy="best_match")
|
|
109
109
|
matcher = IntentMatcher(config)
|
|
@@ -134,7 +134,7 @@ class TestEntityResolution:
|
|
|
134
134
|
Entity("analyze", "analyzer.analyze", "function", 1.0),
|
|
135
135
|
],
|
|
136
136
|
"class": [
|
|
137
|
-
Entity("Pipeline", "
|
|
137
|
+
Entity("Pipeline", "code2llm.Pipeline", "class", 1.0),
|
|
138
138
|
],
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -148,7 +148,7 @@ class TestEntityResolution:
|
|
|
148
148
|
|
|
149
149
|
def test_step_3b_name_match_threshold(self, mock_entities):
|
|
150
150
|
"""3b. Name matching threshold."""
|
|
151
|
-
from
|
|
151
|
+
from code2llm.nlp.config import EntityResolutionConfig
|
|
152
152
|
|
|
153
153
|
config = EntityResolutionConfig(name_match_threshold=0.9)
|
|
154
154
|
resolver = EntityResolver(config, mock_entities)
|
|
@@ -176,7 +176,7 @@ class TestEntityResolution:
|
|
|
176
176
|
|
|
177
177
|
# Add hierarchical entity
|
|
178
178
|
mock_entities["function"].append(
|
|
179
|
-
Entity("Pipeline.run", "
|
|
179
|
+
Entity("Pipeline.run", "code2llm.Pipeline.run", "function", 1.0)
|
|
180
180
|
)
|
|
181
181
|
|
|
182
182
|
result = resolver.resolve("run method")
|
code2llm-0.3.10/tests/test_sprint3_pipelines.py → code2llm-0.3.11/tests/test_pipeline_detector.py
RENAMED
|
@@ -10,13 +10,13 @@ import textwrap
|
|
|
10
10
|
import pytest
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
|
|
13
|
-
from
|
|
14
|
-
from
|
|
13
|
+
from code2llm.core.models import AnalysisResult, FunctionInfo, ModuleInfo
|
|
14
|
+
from code2llm.analysis.pipeline_detector import (
|
|
15
15
|
PipelineDetector, Pipeline, PipelineStage,
|
|
16
16
|
)
|
|
17
|
-
from
|
|
18
|
-
from
|
|
19
|
-
from
|
|
17
|
+
from code2llm.analysis.side_effects import SideEffectDetector
|
|
18
|
+
from code2llm.analysis.type_inference import TypeInferenceEngine
|
|
19
|
+
from code2llm.exporters.flow_exporter import FlowExporter
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
# ---------------------------------------------------------------------------
|
|
@@ -178,7 +178,7 @@ class TestDomainClassification:
|
|
|
178
178
|
def test_nlp_domain(self):
|
|
179
179
|
funcs = _build_chain_funcs([
|
|
180
180
|
("normalize_query", 2), ("match_intent", 5), ("resolve_entity", 3),
|
|
181
|
-
], module="
|
|
181
|
+
], module="code2llm.nlp")
|
|
182
182
|
detector = PipelineDetector()
|
|
183
183
|
pipelines = detector.detect(funcs)
|
|
184
184
|
|
|
@@ -188,7 +188,7 @@ class TestDomainClassification:
|
|
|
188
188
|
def test_analysis_domain(self):
|
|
189
189
|
funcs = _build_chain_funcs([
|
|
190
190
|
("analyze_file", 4), ("compute_metrics", 6), ("build_call_graph", 3),
|
|
191
|
-
], module="
|
|
191
|
+
], module="code2llm.analysis")
|
|
192
192
|
detector = PipelineDetector()
|
|
193
193
|
pipelines = detector.detect(funcs)
|
|
194
194
|
|
|
@@ -198,7 +198,7 @@ class TestDomainClassification:
|
|
|
198
198
|
def test_export_domain(self):
|
|
199
199
|
funcs = _build_chain_funcs([
|
|
200
200
|
("export_toon", 3), ("render_header", 2), ("format_output", 2),
|
|
201
|
-
], module="
|
|
201
|
+
], module="code2llm.exporters")
|
|
202
202
|
detector = PipelineDetector()
|
|
203
203
|
pipelines = detector.detect(funcs)
|
|
204
204
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pytest
|
|
2
|
-
from
|
|
3
|
-
from
|
|
2
|
+
from code2llm.refactor.prompt_engine import PromptEngine
|
|
3
|
+
from code2llm.core.models import AnalysisResult, CodeSmell, FunctionInfo
|
|
4
4
|
|
|
5
5
|
def test_tiktoken_truncation():
|
|
6
6
|
result = AnalysisResult()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
import ast
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
from
|
|
3
|
+
from code2llm.core.config import Config
|
|
4
|
+
from code2llm.analysis.call_graph import CallGraphExtractor
|
|
5
|
+
from code2llm.analysis.dfg import DFGExtractor
|
|
6
|
+
from code2llm.analysis.smells import SmellDetector
|
|
7
|
+
from code2llm.refactor.prompt_engine import PromptEngine
|
|
8
8
|
|
|
9
9
|
def test_metrics_calculation():
|
|
10
10
|
code = """
|
|
@@ -23,7 +23,7 @@ def c():
|
|
|
23
23
|
|
|
24
24
|
# Manual population of functions (since cg_extractor assumes they are in result.functions)
|
|
25
25
|
# ProjectAnalyzer normally does this merge. For unit test, we simulate:
|
|
26
|
-
from
|
|
26
|
+
from code2llm.core.models import FunctionInfo
|
|
27
27
|
result.functions = {
|
|
28
28
|
"test.a": FunctionInfo(name="a", qualified_name="test.a", file="test.py", line=2, calls=["test.b", "test.c"]),
|
|
29
29
|
"test.b": FunctionInfo(name="b", qualified_name="test.b", file="test.py", line=5, calls=[]),
|
|
@@ -55,7 +55,7 @@ def update_data(obj):
|
|
|
55
55
|
assert "method_call" in types # .append()
|
|
56
56
|
|
|
57
57
|
def test_smell_detection():
|
|
58
|
-
from
|
|
58
|
+
from code2llm.core.models import AnalysisResult, FunctionInfo, Mutation
|
|
59
59
|
result = AnalysisResult(project_path=".", analysis_mode="static")
|
|
60
60
|
result.functions = {
|
|
61
61
|
"test.god_func": FunctionInfo(name="god_func", qualified_name="test.god_func", file="test.py", line=10)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Tests for ToonExporter v2 format."""
|
|
2
2
|
import pytest
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from
|
|
5
|
-
from
|
|
4
|
+
from code2llm.core.models import AnalysisResult, FunctionInfo, ClassInfo, ModuleInfo
|
|
5
|
+
from code2llm.exporters.toon import ToonExporter, EXCLUDE_PATTERNS
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
@pytest.fixture
|
|
@@ -91,7 +91,7 @@ class TestToonExporterV2:
|
|
|
91
91
|
lines = content.split("\n")
|
|
92
92
|
|
|
93
93
|
# Check header
|
|
94
|
-
assert lines[0].startswith("#
|
|
94
|
+
assert lines[0].startswith("# code2llm |")
|
|
95
95
|
assert "CC" in lines[1]
|
|
96
96
|
assert "critical:" in lines[1]
|
|
97
97
|
|
|
@@ -182,12 +182,12 @@ class TestToonExporterV2:
|
|
|
182
182
|
"""Test that normal project paths are included."""
|
|
183
183
|
exporter = ToonExporter()
|
|
184
184
|
|
|
185
|
-
assert exporter._is_excluded("/project/
|
|
185
|
+
assert exporter._is_excluded("/project/code2llm/analyzer.py") is False
|
|
186
186
|
assert exporter._is_excluded("/project/tests/test_analyzer.py") is False
|
|
187
187
|
|
|
188
188
|
def test_max_health_issues_limit(self, sample_result, tmp_path):
|
|
189
189
|
"""Test that HEALTH section respects MAX_HEALTH_ISSUES limit."""
|
|
190
|
-
from
|
|
190
|
+
from code2llm.exporters.toon import MAX_HEALTH_ISSUES
|
|
191
191
|
|
|
192
192
|
# Add many high CC functions
|
|
193
193
|
for i in range(100):
|
|
@@ -213,7 +213,7 @@ class TestToonExporterV2:
|
|
|
213
213
|
|
|
214
214
|
def test_coupling_matrix_limited(self, sample_result, tmp_path):
|
|
215
215
|
"""Test that COUPLING matrix is limited to top packages."""
|
|
216
|
-
from
|
|
216
|
+
from code2llm.exporters.toon import MAX_COUPLING_PACKAGES
|
|
217
217
|
|
|
218
218
|
exporter = ToonExporter()
|
|
219
219
|
output_file = tmp_path / "test.toon"
|
|
File without changes
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
"""Graph visualization using NetworkX and matplotlib."""
|
|
2
|
-
|
|
3
|
-
import matplotlib.pyplot as plt
|
|
4
|
-
import matplotlib.patches as patches
|
|
5
|
-
import networkx as nx
|
|
6
|
-
from typing import Dict
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
from ..core.models import AnalysisResult
|
|
10
|
-
from ..core.config import NODE_COLORS
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class GraphVisualizer:
|
|
14
|
-
"""Visualize analysis results as graphs."""
|
|
15
|
-
|
|
16
|
-
def __init__(self, result: AnalysisResult):
|
|
17
|
-
self.result = result
|
|
18
|
-
self.graph = nx.DiGraph()
|
|
19
|
-
self._build_graph()
|
|
20
|
-
|
|
21
|
-
def _build_graph(self):
|
|
22
|
-
"""Build NetworkX graph from analysis result."""
|
|
23
|
-
# Add nodes
|
|
24
|
-
for node_id, node in self.result.nodes.items():
|
|
25
|
-
color = NODE_COLORS.get(node.type, '#757575')
|
|
26
|
-
self.graph.add_node(
|
|
27
|
-
node_id,
|
|
28
|
-
label=node.label[:30],
|
|
29
|
-
type=node.type,
|
|
30
|
-
color=color,
|
|
31
|
-
function=node.function
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
# Add edges
|
|
35
|
-
for edge in self.result.edges:
|
|
36
|
-
self.graph.add_edge(
|
|
37
|
-
edge.source,
|
|
38
|
-
edge.target,
|
|
39
|
-
edge_type=edge.edge_type,
|
|
40
|
-
conditions=edge.conditions
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
def visualize_cfg(self, filepath: str, layout: str = 'spring'):
|
|
44
|
-
"""Create control flow visualization."""
|
|
45
|
-
plt.figure(figsize=(16, 12))
|
|
46
|
-
|
|
47
|
-
# Choose layout
|
|
48
|
-
if layout == 'spring':
|
|
49
|
-
pos = nx.spring_layout(self.graph, k=2, iterations=50, seed=42)
|
|
50
|
-
elif layout == 'hierarchical':
|
|
51
|
-
pos = self._hierarchical_layout()
|
|
52
|
-
elif layout == 'kamada':
|
|
53
|
-
pos = nx.kamada_kawai_layout(self.graph)
|
|
54
|
-
else:
|
|
55
|
-
pos = nx.shell_layout(self.graph)
|
|
56
|
-
|
|
57
|
-
# Get node colors
|
|
58
|
-
node_colors = []
|
|
59
|
-
for node_id in self.graph.nodes():
|
|
60
|
-
node_type = self.graph.nodes[node_id].get('type', 'DEFAULT')
|
|
61
|
-
node_colors.append(NODE_COLORS.get(node_type, '#757575'))
|
|
62
|
-
|
|
63
|
-
# Draw graph
|
|
64
|
-
nx.draw_networkx_nodes(
|
|
65
|
-
self.graph, pos,
|
|
66
|
-
node_color=node_colors,
|
|
67
|
-
node_size=600,
|
|
68
|
-
alpha=0.8,
|
|
69
|
-
edgecolors='white',
|
|
70
|
-
linewidths=2
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
nx.draw_networkx_edges(
|
|
74
|
-
self.graph, pos,
|
|
75
|
-
alpha=0.4,
|
|
76
|
-
arrows=True,
|
|
77
|
-
arrowsize=15,
|
|
78
|
-
arrowstyle='->',
|
|
79
|
-
edge_color='#666666',
|
|
80
|
-
width=1.5
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
# Draw labels for important nodes
|
|
84
|
-
labels = {}
|
|
85
|
-
for node_id in self.graph.nodes():
|
|
86
|
-
node_data = self.graph.nodes[node_id]
|
|
87
|
-
if node_data.get('type') in ['FUNC', 'IF', 'CALL']:
|
|
88
|
-
label = node_data.get('label', '') or ''
|
|
89
|
-
labels[node_id] = label[:25]
|
|
90
|
-
|
|
91
|
-
nx.draw_networkx_labels(
|
|
92
|
-
self.graph, pos, labels,
|
|
93
|
-
font_size=8,
|
|
94
|
-
font_color='white',
|
|
95
|
-
font_weight='bold'
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
# Add legend
|
|
99
|
-
legend_elements = [
|
|
100
|
-
patches.Patch(color=NODE_COLORS['FUNC'], label='Function'),
|
|
101
|
-
patches.Patch(color=NODE_COLORS['CALL'], label='Call'),
|
|
102
|
-
patches.Patch(color=NODE_COLORS['IF'], label='Decision'),
|
|
103
|
-
patches.Patch(color=NODE_COLORS['FOR'], label='Loop'),
|
|
104
|
-
patches.Patch(color=NODE_COLORS['RETURN'], label='Return')
|
|
105
|
-
]
|
|
106
|
-
plt.legend(handles=legend_elements, loc='upper right', fontsize=10)
|
|
107
|
-
|
|
108
|
-
plt.title('Control Flow Graph', fontsize=16, fontweight='bold')
|
|
109
|
-
plt.axis('off')
|
|
110
|
-
plt.tight_layout()
|
|
111
|
-
plt.savefig(filepath, dpi=300, bbox_inches='tight', facecolor='white')
|
|
112
|
-
plt.close()
|
|
113
|
-
|
|
114
|
-
def visualize_call_graph(self, filepath: str):
|
|
115
|
-
"""Visualize call graph."""
|
|
116
|
-
# Build call graph
|
|
117
|
-
call_graph = nx.DiGraph()
|
|
118
|
-
|
|
119
|
-
for func_name, func_info in self.result.functions.items():
|
|
120
|
-
short_name = func_name.split('.')[-1]
|
|
121
|
-
call_graph.add_node(func_name, label=short_name)
|
|
122
|
-
|
|
123
|
-
for callee in func_info.calls:
|
|
124
|
-
call_graph.add_edge(func_name, callee)
|
|
125
|
-
|
|
126
|
-
if len(call_graph.nodes()) == 0:
|
|
127
|
-
return # Nothing to visualize
|
|
128
|
-
|
|
129
|
-
plt.figure(figsize=(14, 10))
|
|
130
|
-
|
|
131
|
-
# Layout
|
|
132
|
-
pos = nx.spring_layout(call_graph, k=1.5, iterations=50, seed=42)
|
|
133
|
-
|
|
134
|
-
# Node sizes based on calls
|
|
135
|
-
node_sizes = []
|
|
136
|
-
for node in call_graph.nodes():
|
|
137
|
-
out_degree = call_graph.out_degree(node)
|
|
138
|
-
in_degree = call_graph.in_degree(node)
|
|
139
|
-
size = 300 + (out_degree + in_degree) * 150
|
|
140
|
-
node_sizes.append(size)
|
|
141
|
-
|
|
142
|
-
# Draw
|
|
143
|
-
nx.draw_networkx_nodes(
|
|
144
|
-
call_graph, pos,
|
|
145
|
-
node_color='#4CAF50',
|
|
146
|
-
node_size=node_sizes,
|
|
147
|
-
alpha=0.8,
|
|
148
|
-
edgecolors='white',
|
|
149
|
-
linewidths=2
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
nx.draw_networkx_edges(
|
|
153
|
-
call_graph, pos,
|
|
154
|
-
alpha=0.5,
|
|
155
|
-
arrows=True,
|
|
156
|
-
arrowsize=20,
|
|
157
|
-
edge_color='#2196F3',
|
|
158
|
-
width=2
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
# Labels
|
|
162
|
-
labels = {n: (call_graph.nodes[n].get('label') or n)[:20] for n in call_graph.nodes()}
|
|
163
|
-
nx.draw_networkx_labels(
|
|
164
|
-
call_graph, pos, labels,
|
|
165
|
-
font_size=9,
|
|
166
|
-
font_weight='bold'
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
plt.title('Function Call Graph', fontsize=16, fontweight='bold')
|
|
170
|
-
plt.axis('off')
|
|
171
|
-
plt.tight_layout()
|
|
172
|
-
plt.savefig(filepath, dpi=300, bbox_inches='tight', facecolor='white')
|
|
173
|
-
plt.close()
|
|
174
|
-
|
|
175
|
-
def _hierarchical_layout(self) -> Dict:
|
|
176
|
-
"""Create hierarchical layout grouped by function."""
|
|
177
|
-
from collections import defaultdict
|
|
178
|
-
|
|
179
|
-
# Group nodes by function
|
|
180
|
-
function_groups = defaultdict(list)
|
|
181
|
-
for node_id, node in self.result.nodes.items():
|
|
182
|
-
func = node.function or '__global__'
|
|
183
|
-
function_groups[func].append(node_id)
|
|
184
|
-
|
|
185
|
-
# Position nodes
|
|
186
|
-
pos = {}
|
|
187
|
-
y_offset = 0
|
|
188
|
-
|
|
189
|
-
for func_name, nodes in sorted(function_groups.items()):
|
|
190
|
-
for i, node_id in enumerate(nodes):
|
|
191
|
-
x = i * 2
|
|
192
|
-
y = -y_offset
|
|
193
|
-
pos[node_id] = (x, y)
|
|
194
|
-
y_offset += 3
|
|
195
|
-
|
|
196
|
-
return pos
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
LICENSE
|
|
2
|
-
README.md
|
|
3
|
-
pyproject.toml
|
|
4
|
-
setup.py
|
|
5
|
-
code2flow/__init__.py
|
|
6
|
-
code2flow/__main__.py
|
|
7
|
-
code2flow/cli.py
|
|
8
|
-
code2flow/llm_flow_generator.py
|
|
9
|
-
code2flow/llm_task_generator.py
|
|
10
|
-
code2flow/mermaid_generator.py
|
|
11
|
-
code2flow/analysis/__init__.py
|
|
12
|
-
code2flow/analysis/call_graph.py
|
|
13
|
-
code2flow/analysis/cfg.py
|
|
14
|
-
code2flow/analysis/coupling.py
|
|
15
|
-
code2flow/analysis/data_analysis.py
|
|
16
|
-
code2flow/analysis/dfg.py
|
|
17
|
-
code2flow/analysis/pipeline_detector.py
|
|
18
|
-
code2flow/analysis/side_effects.py
|
|
19
|
-
code2flow/analysis/smells.py
|
|
20
|
-
code2flow/analysis/type_inference.py
|
|
21
|
-
code2flow/core/__init__.py
|
|
22
|
-
code2flow/core/analyzer.py
|
|
23
|
-
code2flow/core/config.py
|
|
24
|
-
code2flow/core/models.py
|
|
25
|
-
code2flow/core/streaming_analyzer.py
|
|
26
|
-
code2flow/exporters/__init__.py
|
|
27
|
-
code2flow/exporters/base.py
|
|
28
|
-
code2flow/exporters/context_exporter.py
|
|
29
|
-
code2flow/exporters/flow_exporter.py
|
|
30
|
-
code2flow/exporters/json_exporter.py
|
|
31
|
-
code2flow/exporters/llm_exporter.py
|
|
32
|
-
code2flow/exporters/map_exporter.py
|
|
33
|
-
code2flow/exporters/mermaid_exporter.py
|
|
34
|
-
code2flow/exporters/toon.py
|
|
35
|
-
code2flow/exporters/yaml_exporter.py
|
|
36
|
-
code2flow/nlp/__init__.py
|
|
37
|
-
code2flow/nlp/config.py
|
|
38
|
-
code2flow/nlp/entity_resolution.py
|
|
39
|
-
code2flow/nlp/intent_matching.py
|
|
40
|
-
code2flow/nlp/normalization.py
|
|
41
|
-
code2flow/nlp/pipeline.py
|
|
42
|
-
code2flow/patterns/__init__.py
|
|
43
|
-
code2flow/patterns/detector.py
|
|
44
|
-
code2flow/refactor/__init__.py
|
|
45
|
-
code2flow/refactor/prompt_engine.py
|
|
46
|
-
code2flow/visualizers/__init__.py
|
|
47
|
-
code2flow/visualizers/graph.py
|
|
48
|
-
code2llm.egg-info/PKG-INFO
|
|
49
|
-
code2llm.egg-info/SOURCES.txt
|
|
50
|
-
code2llm.egg-info/dependency_links.txt
|
|
51
|
-
code2llm.egg-info/entry_points.txt
|
|
52
|
-
code2llm.egg-info/requires.txt
|
|
53
|
-
code2llm.egg-info/top_level.txt
|
|
54
|
-
tests/test_advanced_analysis.py
|
|
55
|
-
tests/test_analyzer.py
|
|
56
|
-
tests/test_edge_cases.py
|
|
57
|
-
tests/test_format_quality.py
|
|
58
|
-
tests/test_nlp_pipeline.py
|
|
59
|
-
tests/test_refactoring_engine.py
|
|
60
|
-
tests/test_sprint2_flow.py
|
|
61
|
-
tests/test_sprint3_pipelines.py
|
|
62
|
-
tests/test_sprint4.py
|
|
63
|
-
tests/test_sprint5.py
|
|
64
|
-
tests/test_toon_v2.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
code2flow
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/code2llm-0.3.10/code2flow/llm_task_generator.py → /code2llm-0.3.11/code2llm/generators/llm_task.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|