graphlint 0.3.0__tar.gz → 0.3.2__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.
- {graphlint-0.3.0 → graphlint-0.3.2}/CHANGELOG.md +275 -243
- {graphlint-0.3.0/graphlint.egg-info → graphlint-0.3.2}/PKG-INFO +4 -3
- {graphlint-0.3.0 → graphlint-0.3.2}/README.md +200 -199
- {graphlint-0.3.0 → graphlint-0.3.2}/README_PYPI.md +200 -199
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/architecture/overview.md +51 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/README.md +200 -199
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/architecture/overview.md +44 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/__init__.py +1 -1
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/_graph_algo.py +43 -23
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/graph.py +595 -594
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/imports.py +14 -1
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/constants.py +317 -258
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/entry.py +360 -332
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/imports.py +171 -171
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/api.py +12 -2
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/config/defaults.py +7 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/incremental/_db_ops.py +35 -1
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/incremental/indexer.py +421 -381
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/query/engine.py +56 -28
- {graphlint-0.3.0 → graphlint-0.3.2/graphlint.egg-info}/PKG-INFO +4 -3
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/requires.txt +1 -1
- {graphlint-0.3.0 → graphlint-0.3.2}/pyproject.toml +2 -2
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_engine.py +86 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_imports.py +43 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/CONTRIBUTING.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/LICENSE +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/MANIFEST.in +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/api/build.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/api/configure.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/api/exceptions.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/api/query.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/cli/usage.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/agent-integration.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/configuration.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/entry-detection.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/getting-started.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/warnings.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/index.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/api/build.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/api/configure.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/api/exceptions.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/api/query.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/cli/usage.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/agent-integration.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/configuration.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/entry-detection.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/getting-started.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/warnings.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/index.md +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/agent_tools.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/_types.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/base.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/constants.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/decorators.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/entry.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/parser.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/visitor.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/registry.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/parser.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/visitor.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/warnings.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/cli.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/config/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/config/manager.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/exceptions.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/i18n/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/i18n/en.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/i18n/zh_CN.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/incremental/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/params.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/query/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/query/formatter.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/query/volume.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/storage/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/storage/db.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/storage/hashing.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/storage/schema.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/SOURCES.txt +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/dependency_links.txt +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/entry_points.txt +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/top_level.txt +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/setup.cfg +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_api.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_cli.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_data_transfer.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_dead_code_query.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_full_pipeline.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_incremental.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_json_output.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/performance/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/performance/test_large_codebase.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/__init__.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_auto_build.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_config.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_db.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_db_ops.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_decorators.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_entry_detect.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_exceptions.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_formatter.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_graph.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_graph_algo.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_hashing.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_i18n.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_mock_boundary.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_params.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_parser.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_schema.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_volume.py +0 -0
- {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_warnings.py +0 -0
|
@@ -1,243 +1,275 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
## [0.3.
|
|
6
|
-
|
|
7
|
-
###
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
- `
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- `
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
### Changed
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
-
|
|
96
|
-
|
|
97
|
-
- `
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
## [0.1.
|
|
125
|
-
|
|
126
|
-
### Fixed
|
|
127
|
-
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
- `
|
|
150
|
-
-
|
|
151
|
-
|
|
152
|
-
### Fixed
|
|
153
|
-
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
## [0.1.
|
|
157
|
-
|
|
158
|
-
### Fixed
|
|
159
|
-
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
-
|
|
163
|
-
- Python
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
-
|
|
181
|
-
-
|
|
182
|
-
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
- `
|
|
186
|
-
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
- Module
|
|
192
|
-
-
|
|
193
|
-
- Module-level
|
|
194
|
-
-
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
- `
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
- `
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
-
|
|
214
|
-
-
|
|
215
|
-
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
-
|
|
224
|
-
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
-
|
|
230
|
-
-
|
|
231
|
-
-
|
|
232
|
-
-
|
|
233
|
-
-
|
|
234
|
-
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.3.2] - 2026-07-25
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- First-time builds now run a full rebuild; all subsequent queries use
|
|
9
|
+
incremental mode (previously every query forced a full rebuild)
|
|
10
|
+
- Incremental rebuild restructured into 6 clearly delineated phases: Remove →
|
|
11
|
+
Parse → Downstream Reconnect → Rebuild → Persist → Verify
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- Incremental rebuild: empty `set()` passed as `changed_files` was treated as
|
|
15
|
+
falsy and replaced with all files, causing unnecessary full re-parse
|
|
16
|
+
- Incremental rebuild: unchanged child nodes whose parent received a new ID in
|
|
17
|
+
a changed file had stale `parent_node_id` values in the database (in-memory
|
|
18
|
+
remapping was not written back)
|
|
19
|
+
- Incremental rebuild: removed files were not included in downstream
|
|
20
|
+
reconnection, causing FOREIGN KEY violations when prebuilt edges referenced
|
|
21
|
+
deleted symbols
|
|
22
|
+
|
|
23
|
+
## [0.3.1] - 2026-07-24
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- Cargo workspace detection: `[[bin]]` path entries in `Cargo.toml` are now
|
|
27
|
+
recognized as Rust language entry points
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- SQLite `IN` clause batching: queries with >999 variables are now split into
|
|
31
|
+
batches to avoid the SQLite variable limit, preventing crashes on large
|
|
32
|
+
codebases
|
|
33
|
+
- Dotted imports (`import X.Y.Z`) are now correctly detected as used, fixing
|
|
34
|
+
false-positive `unused_import` warnings for multi-level imports
|
|
35
|
+
- Relaxed `tree-sitter-rust` version bound to allow Rust grammar v15+
|
|
36
|
+
|
|
37
|
+
## [0.3.0] - 2026-07-23
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- Experimental Rust language analysis via `tree-sitter-rust` (opt-in via `[rust]`
|
|
41
|
+
optional dependency group)
|
|
42
|
+
- `query --public-as-entry` option: treats all public functions/methods as entry
|
|
43
|
+
points for dead-code reachability analysis
|
|
44
|
+
- `pub_api` entry rule template (disabled by default) for projects that want
|
|
45
|
+
public API surface as the primary entry
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## [0.2.0] - 2026-07-22
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
- Multi-language architecture: `LanguageAdapter` abstract base class and
|
|
52
|
+
`LanguageRegistry` for extension-based routing of source files to language
|
|
53
|
+
backends, laying the foundation for future multi-language support
|
|
54
|
+
- `language/python/` package: Python-specific adapter, parser, entry detector,
|
|
55
|
+
imports analyzer, decorators resolver, and constants — decoupled from the
|
|
56
|
+
core framework
|
|
57
|
+
- Per-language `constants.py`: configurable public API dunders, special
|
|
58
|
+
methods, and test-file detection
|
|
59
|
+
- Type annotation awareness in AST visitor: automatically resolves unpacked
|
|
60
|
+
variable types (e.g., loop bindings, tuple unpacking) for more accurate
|
|
61
|
+
read/write edge tracking
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
- **[Breaking]** Analyzer modules reorganized: `parser.py`, `entry_detect.py`,
|
|
65
|
+
`imports.py`, `decorators.py`, `visitor.py` moved into `language/python/` —
|
|
66
|
+
direct imports of old module paths will break
|
|
67
|
+
- Entry point rules now serve as initialization template only: rules are
|
|
68
|
+
written to `.graphlint/config.json` on first build, after which the config
|
|
69
|
+
file is the single source of truth
|
|
70
|
+
- Default entry strategy simplified: entry rules are no longer hardcoded in
|
|
71
|
+
the indexer; they come solely from runtime configuration
|
|
72
|
+
- `GraphBuilder` no longer owns entry detection — entry points are resolved
|
|
73
|
+
through the language adapter
|
|
74
|
+
- `WarningCollector` simplified: language-specific constant tables moved to
|
|
75
|
+
`language/python/constants.py`
|
|
76
|
+
|
|
77
|
+
## [0.1.12] - 2026-07-21
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
- `query --fail-on <warn-types>` option: returns exit code `2` when matching
|
|
81
|
+
warning types are found in query results, enabling CI pipeline integration
|
|
82
|
+
- `graphlint config` subcommands now return exit code `1` on error (previously
|
|
83
|
+
always returned `0`)
|
|
84
|
+
|
|
85
|
+
## [0.1.11] - 2026-07-21
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
- Entry point detection now uses a unified pattern-driven architecture — all
|
|
89
|
+
rules (built-in and custom) share the same `_detect_custom` code path
|
|
90
|
+
- Built-in detectors replaced with declarative `ast_pattern` expressions using
|
|
91
|
+
the existing prefix syntax (`function_call:`, `decorator:`, `if_name_main`,
|
|
92
|
+
`file_match:`, `test_file`)
|
|
93
|
+
- `ast_pattern` supports OR combinations with ` | ` separator (e.g.
|
|
94
|
+
`class_instantiation:FastAPI | function_call:uvicorn.run`)
|
|
95
|
+
- `ast_pattern` field is no longer required for entry rules — rules without
|
|
96
|
+
it are silently skipped instead of failing validation
|
|
97
|
+
- Decorator matching uses `fnmatch` instead of substring `in`, providing
|
|
98
|
+
precise glob matching and eliminating false positives from partial name
|
|
99
|
+
overlaps
|
|
100
|
+
- `function_call:` and `class_instantiation:` patterns now support `fnmatch`
|
|
101
|
+
globs (was exact match only)
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
- `file_match:` pattern now correctly checks the file path at rule level
|
|
105
|
+
instead of a non-existent `node.filename` attribute, fixing the bug where
|
|
106
|
+
`file_match:` rules never matched
|
|
107
|
+
- `graphlint config copy-from` no longer picks up irrelevant query/analyzer
|
|
108
|
+
parameters, fixing the config copy command exception
|
|
109
|
+
|
|
110
|
+
## [0.1.10] - 2026-07-09
|
|
111
|
+
|
|
112
|
+
### Fixed
|
|
113
|
+
- Assignment target context resolution now correctly distinguishes class fields
|
|
114
|
+
(`self.xxx` / `cls.xxx`), method-local variables, and module-level variables,
|
|
115
|
+
preventing misclassification of `self.x = y` inside methods as local variables
|
|
116
|
+
- Class fields assigned across multiple methods (e.g. `__init__` + `set_x`) are
|
|
117
|
+
now deduplicated to a single node, eliminating duplicate field nodes
|
|
118
|
+
|
|
119
|
+
### Changed
|
|
120
|
+
- Attribute-write edges (`self.xxx = value`) now also emit a `read` edge on
|
|
121
|
+
the parent object (`self`), ensuring proper usage tracking of the containing
|
|
122
|
+
class instance
|
|
123
|
+
|
|
124
|
+
## [0.1.9] - 2026-07-08
|
|
125
|
+
|
|
126
|
+
### Fixed
|
|
127
|
+
- FOREIGN KEY constraint failure on incremental rebuilds — prebuilt edge
|
|
128
|
+
remapping now correctly writes remapped node IDs into edge objects
|
|
129
|
+
- `_insert_nodes` node-to-file key collision when multiple changed files
|
|
130
|
+
share the same qualified name and line number
|
|
131
|
+
|
|
132
|
+
### Changed
|
|
133
|
+
- Incremental rebuild now parses only changed files instead of all files
|
|
134
|
+
- Filesystem scan merged into a single `os.walk` pass instead of two
|
|
135
|
+
- Redundant file hash computation eliminated in both full and incremental paths
|
|
136
|
+
|
|
137
|
+
### Added
|
|
138
|
+
- `component_members` table in SQLite schema for future incremental
|
|
139
|
+
connectivity analysis
|
|
140
|
+
|
|
141
|
+
## [0.1.8] - 2026-07-07
|
|
142
|
+
|
|
143
|
+
### Added
|
|
144
|
+
- Agent prompt auto-update: `install` now scans all installed prompts on start,
|
|
145
|
+
replaces outdated content when its version is below the library version,
|
|
146
|
+
and prints the list of updated agents
|
|
147
|
+
- `install` / `uninstall` interactive selection: support Ctrl+C to abort and
|
|
148
|
+
empty input to cancel; prompt texts are now i18n-localized
|
|
149
|
+
- `graphlint prompt` subcommand to copy the agent prompt to the system clipboard
|
|
150
|
+
- Documentation for agent integration (`docs/*/guide/agent-integration.md`)
|
|
151
|
+
|
|
152
|
+
### Fixed
|
|
153
|
+
- Query deadlock: `_build_edge_mapping` now avoids `result` future list
|
|
154
|
+
mutation under concurrent executor shutdown, preventing infinite waits
|
|
155
|
+
|
|
156
|
+
## [0.1.7] - 2026-07-06
|
|
157
|
+
|
|
158
|
+
### Fixed
|
|
159
|
+
- `_resolve_symbol` scope filtering no longer drops cross-class `call` edges
|
|
160
|
+
when a method resolves a same-named call via a different class (registry
|
|
161
|
+
/ dispatch pattern) — all suffix-matched candidates are now included
|
|
162
|
+
- Entry point `file_pattern` matching (`**/*.py` via fnmatch) now also
|
|
163
|
+
matches root-level Python files, not only files in subdirectories
|
|
164
|
+
|
|
165
|
+
## [0.1.6] - 2026-07-05
|
|
166
|
+
|
|
167
|
+
### Changed
|
|
168
|
+
- `ThreadPoolExecutor` replaced with `ProcessPoolExecutor` for edge building
|
|
169
|
+
- Incremental builds on file change now trigger a full rebuild instead of loading prebuilt edges
|
|
170
|
+
- Module-level usage expansion in connected-component analysis uses a Counter to distinguish real references from synthetic edges
|
|
171
|
+
- Dead-code merge loop uses O(1) `comp_by_id` dict lookup instead of O(C) linear scan
|
|
172
|
+
|
|
173
|
+
### Removed
|
|
174
|
+
- `_quick_changed_check()` — mtime-based fast-path stamp was unreliable on Windows NTFS and could trigger unnecessary incremental builds that produced stale edges
|
|
175
|
+
- Ghost-node insertion workaround and stale-edge skip logic in `_do_insert_edges`
|
|
176
|
+
|
|
177
|
+
## [0.1.5] - 2026-07-05
|
|
178
|
+
|
|
179
|
+
### Added
|
|
180
|
+
- `global` keyword support: `visit_Global` handler tracks names declared as `global X` and resolves references to module-level qualified names (`module.X`) instead of local ones, preventing false local node creation
|
|
181
|
+
- `visit_AugAssign` handler for augmented assignment (`X += 1`, `X *= 2`, etc.), generating both read and write references to the target
|
|
182
|
+
- Scope isolation for `global` declarations — `_global_names` is saved/restored on function entry/exit, preventing leakage between functions
|
|
183
|
+
|
|
184
|
+
### Fixed
|
|
185
|
+
- `global X` in functions/methods no longer creates spurious local variable nodes for globally-declared names
|
|
186
|
+
- Augmented assignment (`X += 1`) was silently dropped during AST traversal — now correctly produces both read and write edges
|
|
187
|
+
|
|
188
|
+
## [0.1.4] - 2026-07-04
|
|
189
|
+
|
|
190
|
+
### Fixed
|
|
191
|
+
- Module-level dead code detection: removed synthetic `read` edges from pseudo-node 0 that masked all top-level symbols as "used", enabling detection of genuinely dead module-level functions and variables
|
|
192
|
+
- Module-level write references no longer create unresolvable edges — variable definitions are not treated as write operations, preventing silent edge drops
|
|
193
|
+
- Module-level read/call references now correctly create edges from pseudo-node 0, fixing a false positive where module-level used variables (e.g., `WARN_TYPE_VALUES` read by `VALID_WARN_TYPES = WARN_TYPE_VALUES`) were flagged as dead code
|
|
194
|
+
- Public API dunders (`__all__`, `__version__`, etc.) no longer appear as isolated components — they stay anchored to their file via synthetic containment edges
|
|
195
|
+
- Python special methods (`__init__`, `__enter__`, `__exit__`, etc.) no longer generate redundant dead-code warnings when their parent class is already flagged as unreachable
|
|
196
|
+
- Unreachable classes with special method overloads now produce only the class-level `dead_code` warning, not per-method duplicates
|
|
197
|
+
|
|
198
|
+
## [0.1.3] - 2026-07-04
|
|
199
|
+
|
|
200
|
+
### Added
|
|
201
|
+
- I18n support for CLI parameter help text: `PARAM_DEFS` help strings now go through the i18n system via `help_key`, enabling full language switching for `--help` output
|
|
202
|
+
|
|
203
|
+
### Changed
|
|
204
|
+
- `ParamDef` dataclass: added `help_key` field for i18n key lookup
|
|
205
|
+
- `cli.py:_add_arg()` now resolves help text via `_t(help_key)` when available
|
|
206
|
+
- Updated `en.py` and `zh_CN.py` with all `help.param.*` translation entries
|
|
207
|
+
|
|
208
|
+
## [0.1.2] - 2026-07-04
|
|
209
|
+
|
|
210
|
+
### Added
|
|
211
|
+
- SQLite composite indexes (`idx_edges_source_type`, `idx_edges_target_type`) to accelerate edge-type filtered lookups
|
|
212
|
+
- SQLite single-column index (`idx_warnings_node`) to speed up warnings JOIN queries
|
|
213
|
+
- SQLite sorted indexes (`idx_snapshots_warnings`, `idx_snapshots_nodes`) for faster list_graphs pagination
|
|
214
|
+
- PRAGMA optimizations on Database init: `cache_size=-8000` (8 MB), `mmap_size=268435456` (256 MB), `temp_store=MEMORY`
|
|
215
|
+
- `_quick_changed_check()` — mtime-based fast-path stamp that short-circuits the entire build when no files have changed
|
|
216
|
+
- `_update_scan_stamp()` — persists `{path: mtime_ns}` snapshot inside IndexLock after each successful build
|
|
217
|
+
- `warnings_summary` cache in `QueryEngine.list_graphs()` — lazily computed then shallow-copied, eliminating repeated `GROUP BY` scans
|
|
218
|
+
- `_precompute_edge_counts()` — single-pass edge count per component, replacing O(n × m) per-component iteration
|
|
219
|
+
|
|
220
|
+
### Changed
|
|
221
|
+
- Eliminated second AST traversal: edge building is now driven by `ReferenceInfo` collected during the single `ASTVisitor` pass — removed `_walk`, `_read_edges`, `_proc_call`, `_proc_assign`, `_proc_annassign`, `_target_ids`, `_read_target_expr` (~400 lines). In a large codebase (700+ `.py` files, 1000+ classes, 14,000+ functions), full rebuild time improved from ~2500s to ~200s.
|
|
222
|
+
- `_build_file_edges_worker` now consumes `ParseResult.references` directly instead of re-walking the AST tree
|
|
223
|
+
- Module pseudo-node (id=0) connectivity tightened: liveness only propagates through `read`/`call` edges, not `write` edges — preventing false reachability of write-only variables and fixing false dead-code reports for module-level used variables
|
|
224
|
+
- Connected component BFS no longer unconditionally seeds node 0, avoiding spurious reachability
|
|
225
|
+
- Module-level synthetic edges recreated for all files each build instead of only for unchanged files
|
|
226
|
+
- Optimized multiple AST I/O bottlenecks in source file reading and tree reuse
|
|
227
|
+
- `_symbol_index` / `_suffix_index` from `dict` to `defaultdict(list)`, removing all `.setdefault()` calls
|
|
228
|
+
- `_resolve_symbol` now accepts a per-worker `resolve_cache` dict — repeated `(qname, scope)` pairs are resolved once per file
|
|
229
|
+
- `call_graph` prebuilt once in `find_connected_components` and reused across `compute_entry_reachability` calls, eliminating redundant edge re-traversal
|
|
230
|
+
- `_insert_nodes` uses a pre-built `(qualified_name, line_start) → file_path` map instead of O(n²) linear scan via `_node_path()`
|
|
231
|
+
- Full rebuild (`incremental=False`) now uses per-table `DELETE FROM` instead of per-file `_delete_old` + selective cleanup
|
|
232
|
+
- Incremental build edge insertion now uses global `DELETE FROM edges` instead of per-file partial delete, eliminating dangling old node-ID references
|
|
233
|
+
- `load_prebuilt_edges` accepts optional `sql_to_mem` mapping, simplifying caller in `indexer.py`
|
|
234
|
+
- Agent injection prompt strengthened to warn when graphlint CLI is unavailable
|
|
235
|
+
|
|
236
|
+
### Removed
|
|
237
|
+
- `_node_path()` helper function (replaced by pre-built node-to-file map)
|
|
238
|
+
|
|
239
|
+
### Fixed
|
|
240
|
+
- Windows compatibility: `os.unlink()` with `missing_ok=True` replaced by `if exists()` guard
|
|
241
|
+
|
|
242
|
+
## [0.1.1] - 2026-07-04
|
|
243
|
+
|
|
244
|
+
### Added
|
|
245
|
+
- Parallel edge building via ThreadPoolExecutor for changed files (`performance.parallel_workers`)
|
|
246
|
+
- Multi-level suffix index for improved symbol resolution beyond single-level short names
|
|
247
|
+
- Auto-build retry with full index rebuild on FOREIGN KEY constraint failure
|
|
248
|
+
|
|
249
|
+
### Changed
|
|
250
|
+
- Agent injection prompt wording strengthened to "Always use" with fallback instruction when CLI is unavailable
|
|
251
|
+
- Entry detection methods now reuse pre-parsed source (`pr.source`) to reduce redundant file I/O
|
|
252
|
+
- Refactored AST walk functions to module level to enable parallel execution
|
|
253
|
+
|
|
254
|
+
### Fixed
|
|
255
|
+
- FOREIGN KEY constraint violations in incremental mode by sorting nodes parent-first before DB insert
|
|
256
|
+
- Incremental rebuild no longer rebuilds edges for unchanged files
|
|
257
|
+
|
|
258
|
+
## [0.1.0] - 2026-07-01
|
|
259
|
+
|
|
260
|
+
### Added
|
|
261
|
+
- Initial release
|
|
262
|
+
- AST-based Python source code parsing (classes, functions, methods, variables, fields)
|
|
263
|
+
- Dependency graph construction with 5 edge types (read, write, call, inherit, decorate)
|
|
264
|
+
- 8 built-in entry point detection rules (main, FastAPI, Flask, Django, Click, Typer, Celery, pytest)
|
|
265
|
+
- Custom entry point rules via AST pattern matching
|
|
266
|
+
- 11 warning types (unused_import, dynamic_import, circular_ref, syntax_error, write_only, deprecated_usage, dead_code, type_mismatch, unresolved_ref, unused_variable, file_too_large)
|
|
267
|
+
- Incremental indexing with SHA256-based change detection
|
|
268
|
+
- Adaptive output volume strategy (full, index, truncated)
|
|
269
|
+
- Internationalization (English and Simplified Chinese)
|
|
270
|
+
- CLI interface (`graphlint query`, `graphlint build`, `graphlint config`)
|
|
271
|
+
- Python API (`query()`, `build()`, `configure()`)
|
|
272
|
+
- SQLite persistence with cross-platform file locking
|
|
273
|
+
- Parallel file parsing via ProcessPoolExecutor
|
|
274
|
+
- Configuration management with dot-notation key access
|
|
275
|
+
- Comprehensive test suite (unit, integration, performance)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphlint
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: A static analysis tool for identifying dead code in a codebase. It provides Python API and CLI for use by agents.
|
|
5
5
|
Author-email: Yutong Zou <yutong.zou.24@alumni.ucl.ac.uk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -28,7 +28,7 @@ Provides-Extra: dev
|
|
|
28
28
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
29
29
|
Requires-Dist: pytest-cov>=4; extra == "dev"
|
|
30
30
|
Provides-Extra: rust
|
|
31
|
-
Requires-Dist: tree-sitter<0.
|
|
31
|
+
Requires-Dist: tree-sitter<0.27,>=0.22; extra == "rust"
|
|
32
32
|
Requires-Dist: tree-sitter-rust<0.25,>=0.22; extra == "rust"
|
|
33
33
|
Dynamic: license-file
|
|
34
34
|
|
|
@@ -64,6 +64,7 @@ Install with Rust support: `pip install graphlint[rust]` (adds `tree-sitter` and
|
|
|
64
64
|
- **Configurable entry templates** — add custom entry rules via `ast_pattern` prefixes including `function_call:`, `function_def:`, `decorator:`, `file_match:`, `visibility:pub` (Rust), `trait_impl:` (Rust), `macro_def:` (Rust), and more
|
|
65
65
|
- **`--public-as-entry` flag** — treat all public items (Rust `pub`) as entry points for library-crate analysis
|
|
66
66
|
- **Warning detection** — 11 warning types including circular references, unused imports, write-only variables, and more
|
|
67
|
+
- **Incremental updates** — after initial full scan, only changed files are re-indexed; subsequent queries leverage cached data to minimize computation overhead
|
|
67
68
|
- **Python API + CLI** — integrate into any Tool, CI pipeline, or let agents self-analyze and self-clean
|
|
68
69
|
|
|
69
70
|
## Installation
|
|
@@ -220,7 +221,7 @@ Full documentation is available in the [docs/](https://github.com/AngelosZou/gra
|
|
|
220
221
|
- **Python dynamic imports** — due to Python's dynamic import mechanisms (`importlib`, `getattr`, metaclasses, etc.), the default entry templates may produce false positives in codebases that rely heavily on runtime dispatch. Users should tune the `entry_rules` configuration to match their project's conventions.
|
|
221
222
|
- **Rust macro expansion** — tree-sitter parses unexpanded source; procedural macros and `macro_rules!` bodies appear as opaque token trees. Some macro-generated call paths may be missed. `#[derive]` attributes are partially recognized via implicit `inherit` edges.
|
|
222
223
|
- **`--public-as-entry` scope** — this flag only applies to languages with `public` visibility declarations (Rust `pub`). It has no effect on Python files. Toggling this flag triggers a full re-index. For long-term library-crate analysis, prefer enabling the `rust_pub_api` entry rule via `graphlint config` to persist the setting.
|
|
223
|
-
- **Large codebase build time** — on a large codebase with 700+ `.py` files, 1,000+ classes, and 14,000+ functions, a full rebuild takes approximately 200 seconds (actual performance depends on hardware). Small projects (~60 files) complete in ~1 second.
|
|
224
|
+
- **Large codebase build time** — on a large codebase with 700+ `.py` files, 1,000+ classes, and 14,000+ functions, a full rebuild takes approximately 200 seconds (actual performance depends on hardware). Small projects (~60 files) complete in ~1 second. This cost is one-time, after the initial full scan, subsequent queries use incremental updates.
|
|
224
225
|
|
|
225
226
|
## License
|
|
226
227
|
|