codemap-python 0.1.1__tar.gz → 0.1.3__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.
- {codemap_python-0.1.1 → codemap_python-0.1.3}/PKG-INFO +1 -1
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/call_graph/call_extractor.py +6 -1
- codemap_python-0.1.3/analysis/core/ast_parser.py +31 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/core/import_extractor.py +6 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/explain/explain_runner.py +6 -1
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/runners/phase4_runner.py +6 -1
- codemap_python-0.1.3/analysis/utils/bom_handler.py +55 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/codemap_python.egg-info/PKG-INFO +1 -1
- {codemap_python-0.1.1 → codemap_python-0.1.3}/codemap_python.egg-info/SOURCES.txt +1 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/pyproject.toml +1 -1
- {codemap_python-0.1.1 → codemap_python-0.1.3}/ui/app.py +13 -9
- codemap_python-0.1.1/analysis/core/ast_parser.py +0 -8
- {codemap_python-0.1.1 → codemap_python-0.1.3}/README.md +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/architecture/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/architecture/architecture_engine.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/architecture/dependency_cycles.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/architecture/risk_radar.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/call_graph/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/call_graph/call_graph_builder.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/call_graph/call_resolver.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/call_graph/context_models.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/call_graph/cross_file_resolver.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/call_graph/execution_tracker.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/call_graph/flow_builder.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/call_graph/models.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/core/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/core/ast_context.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/core/class_extractor.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/core/function_extractor.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/explain/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/explain/docstring_extractor.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/explain/repo_summary_generator.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/explain/return_analyzer.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/explain/risk_flags.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/explain/signature_extractor.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/explain/summary_generator.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/graph/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/graph/callgraph_index.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/graph/entrypoint_detector.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/graph/impact_analyzer.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/indexing/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/indexing/import_resolver.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/indexing/symbol_index.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/runners/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/utils/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/utils/ast_helpers.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/utils/cache_manager.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/utils/path_resolver.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/analysis/utils/repo_fetcher.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/cli.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/codemap_cli.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/codemap_python.egg-info/dependency_links.txt +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/codemap_python.egg-info/entry_points.txt +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/codemap_python.egg-info/requires.txt +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/codemap_python.egg-info/top_level.txt +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/security_utils.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/setup.cfg +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_cache_cli_commands.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_cache_retention.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_no_key_persistence.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_registry_session_mode.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_security_cli_integration.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_security_redaction.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_symbol_explain_cache.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_symbol_info_endpoint.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_ui_private_mode_security.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/tests/test_ui_retention_controls.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/ui/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/ui/device_id.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/ui/static/app.js +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/ui/static/styles.css +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/ui/templates/index.html +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/ui/utils/__init__.py +0 -0
- {codemap_python-0.1.1 → codemap_python-0.1.3}/ui/utils/registry_manager.py +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# AST Call detection
|
|
2
2
|
|
|
3
3
|
import ast
|
|
4
|
+
from analysis.utils.bom_handler import remove_bom
|
|
4
5
|
|
|
5
6
|
class FunctionCallVisitor(ast.NodeVisitor):
|
|
6
7
|
def __init__(self, file_path):
|
|
@@ -83,7 +84,11 @@ class FunctionCallVisitor(ast.NodeVisitor):
|
|
|
83
84
|
|
|
84
85
|
def extract_function_calls(file_path):
|
|
85
86
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
86
|
-
|
|
87
|
+
source = f.read()
|
|
88
|
+
|
|
89
|
+
# Remove BOM if present
|
|
90
|
+
source = remove_bom(source)
|
|
91
|
+
tree = ast.parse(source)
|
|
87
92
|
|
|
88
93
|
visitor = FunctionCallVisitor(file_path)
|
|
89
94
|
visitor.visit(tree)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# AST Parser Module
|
|
2
|
+
import ast
|
|
3
|
+
from analysis.utils.bom_handler import remove_bom
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def parse_python_file(file_path):
|
|
7
|
+
"""Parse a Python file, automatically handling UTF-8 BOM.
|
|
8
|
+
|
|
9
|
+
This function:
|
|
10
|
+
1. Reads the file with UTF-8 encoding
|
|
11
|
+
2. Removes any BOM characters automatically
|
|
12
|
+
3. Parses the cleaned source code
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
file_path: Path to Python file to parse
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
ast.Module: Parsed AST tree
|
|
19
|
+
|
|
20
|
+
Raises:
|
|
21
|
+
SyntaxError: If source code has syntax errors
|
|
22
|
+
FileNotFoundError: If file doesn't exist
|
|
23
|
+
"""
|
|
24
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
25
|
+
source = f.read()
|
|
26
|
+
|
|
27
|
+
# Remove BOM if present (handles files from Windows editors, etc.)
|
|
28
|
+
source = remove_bom(source)
|
|
29
|
+
|
|
30
|
+
return ast.parse(source)
|
|
31
|
+
|
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
# analysis/import_extractor.py
|
|
3
3
|
|
|
4
4
|
import ast
|
|
5
|
+
from analysis.utils.bom_handler import remove_bom
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
def extract_imports(file_path):
|
|
9
|
+
"""Extract imports from a Python file, handling UTF-8 BOM automatically."""
|
|
7
10
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
8
11
|
source = f.read()
|
|
9
12
|
|
|
13
|
+
# Remove BOM if present
|
|
14
|
+
source = remove_bom(source)
|
|
15
|
+
|
|
10
16
|
tree = ast.parse(source)
|
|
11
17
|
imports = []
|
|
12
18
|
|
|
@@ -8,6 +8,7 @@ from typing import Optional, Dict, Any
|
|
|
8
8
|
import ast
|
|
9
9
|
import json
|
|
10
10
|
import os
|
|
11
|
+
from analysis.utils.bom_handler import remove_bom
|
|
11
12
|
|
|
12
13
|
from analysis.indexing.symbol_index import SymbolIndex, SymbolInfo
|
|
13
14
|
from analysis.graph.callgraph_index import CallGraphIndex, CallSite
|
|
@@ -27,8 +28,12 @@ def collect_python_files(root_dir: str):
|
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
def parse_ast(file_path: str) -> ast.AST:
|
|
31
|
+
"""Parse a Python file, automatically handling UTF-8 BOM."""
|
|
30
32
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
31
|
-
|
|
33
|
+
source = f.read()
|
|
34
|
+
# Remove BOM if present
|
|
35
|
+
source = remove_bom(source)
|
|
36
|
+
return ast.parse(source)
|
|
32
37
|
|
|
33
38
|
|
|
34
39
|
def file_to_module(file_path: str, repo_root: str) -> str:
|
|
@@ -12,6 +12,7 @@ from analysis.call_graph.cross_file_resolver import CrossFileResolver
|
|
|
12
12
|
from analysis.call_graph.call_extractor import extract_function_calls
|
|
13
13
|
from analysis.core.import_extractor import extract_imports
|
|
14
14
|
from analysis.graph.callgraph_index import build_caller_fqn
|
|
15
|
+
from analysis.utils.bom_handler import remove_bom
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
PROJECT_ROOT = os.path.dirname(os.path.dirname(__file__))
|
|
@@ -29,8 +30,12 @@ def collect_python_files(root_dir: str) -> List[str]:
|
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
def parse_ast(file_path: str):
|
|
33
|
+
"""Parse a Python file, automatically handling UTF-8 BOM."""
|
|
32
34
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
33
|
-
|
|
35
|
+
source = f.read()
|
|
36
|
+
# Remove BOM if present
|
|
37
|
+
source = remove_bom(source)
|
|
38
|
+
return ast.parse(source)
|
|
34
39
|
|
|
35
40
|
|
|
36
41
|
def file_to_module(file_path: str, repo_root: str) -> str:
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""BOM (Byte Order Mark) handling utilities for CodeMap.
|
|
2
|
+
|
|
3
|
+
This module provides utilities to handle UTF-8 BOM characters that are
|
|
4
|
+
sometimes added to Python files by certain editors (especially on Windows).
|
|
5
|
+
|
|
6
|
+
BOM (U+FEFF) is an invisible character that Python's AST parser cannot handle,
|
|
7
|
+
causing: "invalid non-printable character U+FEFF"
|
|
8
|
+
|
|
9
|
+
Solution: Strip BOM before parsing Python files.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def remove_bom(source: str) -> str:
|
|
14
|
+
"""Remove UTF-8 BOM (Byte Order Mark) from source code if present.
|
|
15
|
+
|
|
16
|
+
BOM is a special character (U+FEFF) that some editors (especially Notepad
|
|
17
|
+
on Windows) add to the start of files. Python's AST parser doesn't handle it.
|
|
18
|
+
|
|
19
|
+
This function silently removes it if present, or returns the source unchanged.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
source: Python source code as string
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Source code with BOM removed if present
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
>>> source_with_bom = '\\ufeffdef hello(): pass'
|
|
29
|
+
>>> clean_source = remove_bom(source_with_bom)
|
|
30
|
+
>>> print(clean_source)
|
|
31
|
+
def hello(): pass
|
|
32
|
+
"""
|
|
33
|
+
if source.startswith('\ufeff'):
|
|
34
|
+
return source[1:]
|
|
35
|
+
return source
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def read_source_file(file_path: str) -> str:
|
|
39
|
+
"""Read a Python file and remove BOM if present.
|
|
40
|
+
|
|
41
|
+
This is a convenience function that combines file reading with BOM removal.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
file_path: Path to Python file to read
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Source code with BOM removed
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
FileNotFoundError: If file doesn't exist
|
|
51
|
+
UnicodeDecodeError: If file encoding is not UTF-8
|
|
52
|
+
"""
|
|
53
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
54
|
+
source = f.read()
|
|
55
|
+
return remove_bom(source)
|
|
@@ -42,6 +42,7 @@ analysis/runners/__init__.py
|
|
|
42
42
|
analysis/runners/phase4_runner.py
|
|
43
43
|
analysis/utils/__init__.py
|
|
44
44
|
analysis/utils/ast_helpers.py
|
|
45
|
+
analysis/utils/bom_handler.py
|
|
45
46
|
analysis/utils/cache_manager.py
|
|
46
47
|
analysis/utils/path_resolver.py
|
|
47
48
|
analysis/utils/repo_fetcher.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "codemap-python"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.3"
|
|
8
8
|
description = "Local Python code analysis tool - understand architecture, dependencies, and call graphs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -36,20 +36,24 @@ from security_utils import redact_payload, redact_secrets
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
# Custom cache class that doesn't cache (to avoid TypeError with unhashable Request objects)
|
|
39
|
-
class NoCache:
|
|
40
|
-
"""A cache implementation that doesn't cache anything.
|
|
39
|
+
class NoCache(dict):
|
|
40
|
+
"""A dict-like cache implementation that doesn't actually cache anything.
|
|
41
41
|
|
|
42
42
|
This prevents Jinja2 from trying to cache templates with unhashable objects
|
|
43
|
-
like the Starlette Request in the context.
|
|
43
|
+
like the Starlette Request in the context. Inherits from dict to satisfy
|
|
44
|
+
Jinja2's duck-typing requirements while not actually storing anything.
|
|
44
45
|
"""
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def set(self, key: Any, value: Any, timeout: Any = None) -> None:
|
|
46
|
+
def __setitem__(self, key: Any, value: Any) -> None:
|
|
47
|
+
"""Silently ignore all cache assignments."""
|
|
49
48
|
pass
|
|
50
49
|
|
|
51
|
-
def
|
|
52
|
-
|
|
50
|
+
def __getitem__(self, key: Any) -> Any:
|
|
51
|
+
"""Always return KeyError to indicate cache miss."""
|
|
52
|
+
raise KeyError(key)
|
|
53
|
+
|
|
54
|
+
def get(self, key: Any, default: Any = None) -> Any:
|
|
55
|
+
"""Always return the default value (cache miss)."""
|
|
56
|
+
return default
|
|
53
57
|
|
|
54
58
|
|
|
55
59
|
PROJECT_ROOT = os.path.dirname(os.path.dirname(__file__))
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|