Navegador

navegador / navegador / enrichment / django.py
Blame History Raw 104 lines
1
"""
2
DjangoEnricher — post-ingestion enrichment for Django codebases.
3
4
Promotes generic Function/Class nodes to Django-specific semantic types:
5
- View functions in views.py files
6
- Model classes that inherit from Model
7
- URLPattern functions in urls.py files
8
- Serializer classes in serializers.py files
9
- Task functions decorated with @task or in tasks.py
10
- Admin classes in admin.py files
11
"""
12
13
from navegador.enrichment.base import EnrichmentResult, FrameworkEnricher
14
15
16
class DjangoEnricher(FrameworkEnricher):
17
"""Enriches a navegador graph with Django framework semantics."""
18
19
@property
20
def framework_name(self) -> str:
21
return "django"
22
23
@property
24
def detection_patterns(self) -> list[str]:
25
return ["django", "django.conf", "django.db", "django.http"]
26
27
@property
28
def detection_files(self) -> list[str]:
29
return ["manage.py"]
30
31
def enrich(self) -> EnrichmentResult:
32
result = EnrichmentResult()
33
34
# ── Views ────────────────────────────────────────────────────────────
35
rows = self._query_rows(
36
"MATCH (n:Function) WHERE n.file_path CONTAINS 'views.py' "
37
"RETURN n.name AS name, n.file_path AS file_path"
38
)
39
for name, file_path in rows:
40
self._promote_node(name, file_path, "View")
41
result.patterns_found["views"] = len(rows)
42
result.promoted += len(rows)
43
44
# ── Models ───────────────────────────────────────────────────────────
45
rows = self._query_rows(
46
"MATCH (n:Class)-[:INHERITS]->(b) WHERE b.name CONTAINS 'Model' "
47
"RETURN n.name AS name, n.file_path AS file_path"
48
)
49
for name, file_path in rows:
50
self._promote_node(name, file_path, "Model")
51
result.patterns_found["models"] = len(rows)
52
result.promoted += len(rows)
53
54
# ── URL patterns ─────────────────────────────────────────────────────
55
rows = self._query_rows(
56
"MATCH (n:Function) WHERE n.file_path CONTAINS 'urls.py' "
57
"RETURN n.name AS name, n.file_path AS file_path"
58
)
59
for name, file_path in rows:
60
self._promote_node(name, file_path, "URLPattern")
61
result.patterns_found["url_patterns"] = len(rows)
62
result.promoted += len(rows)
63
64
# ── Serializers ──────────────────────────────────────────────────────
65
rows = self._query_rows(
66
"MATCH (n:Class) WHERE n.file_path CONTAINS 'serializers.py' "
67
"RETURN n.name AS name, n.file_path AS file_path"
68
)
69
for name, file_path in rows:
70
self._promote_node(name, file_path, "Serializer")
71
result.patterns_found["serializers"] = len(rows)
72
result.promoted += len(rows)
73
74
# ── Tasks (decorator or tasks.py) ─────────────────────────────────
75
rows = self._query_rows(
76
"MATCH (n:Function) WHERE n.file_path CONTAINS 'tasks.py' "
77
"OR (n.decorators IS NOT NULL AND n.decorators CONTAINS 'task') "
78
"RETURN n.name AS name, n.file_path AS file_path"
79
)
80
for name, file_path in rows:
81
self._promote_node(name, file_path, "Task")
82
result.patterns_found["tasks"] = len(rows)
83
result.promoted += len(rows)
84
85
# ── Admin ─────────────────────────────────────────────────────────
86
rows = self._query_rows(
87
"MATCH (n:Class) WHERE n.file_path CONTAINS 'admin.py' "
88
"RETURN n.name AS name, n.file_path AS file_path"
89
)
90
for name, file_path in rows:
91
self._promote_node(name, file_path, "Admin")
92
result.patterns_found["admin"] = len(rows)
93
result.promoted += len(rows)
94
95
return result
96
97
# ── Internal helpers ──────────────────────────────────────────────────────
98
99
def _query_rows(self, cypher: str) -> list[tuple[str, str]]:
100
"""Run a Cypher query and return (name, file_path) pairs."""
101
query_result = self.store.query(cypher)
102
rows = query_result.result_set or []
103
return [(row[0], row[1]) for row in rows]
104

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button