refactorlens 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,286 @@
1
+ Metadata-Version: 2.5
2
+ Name: refactorlens
3
+ Version: 0.1.0
4
+ Summary: Metric-grounded AI code review CLI for Python codebases.
5
+ Project-URL: Homepage, https://github.com/okngms/refactorlens
6
+ Project-URL: Source, https://github.com/okngms/refactorlens
7
+ Project-URL: Issues, https://github.com/okngms/refactorlens/issues
8
+ Author-email: Okan GUMUS <okanngumus4@gmail.com>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 RefactorLens contributors
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: code-quality,llm,metrics,refactoring,static-analysis
32
+ Classifier: Development Status :: 3 - Alpha
33
+ Classifier: Environment :: Console
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Programming Language :: Python :: 3.14
40
+ Classifier: Topic :: Software Development :: Quality Assurance
41
+ Requires-Python: >=3.11
42
+ Requires-Dist: httpx>=0.27
43
+ Requires-Dist: pyyaml>=6.0
44
+ Requires-Dist: rich>=13.7
45
+ Requires-Dist: typer>=0.12
46
+ Provides-Extra: dev
47
+ Requires-Dist: pytest>=8.0; extra == 'dev'
48
+ Requires-Dist: ruff>=0.6; extra == 'dev'
49
+ Description-Content-Type: text/markdown
50
+
51
+ # RefactorLens
52
+
53
+ **Metric-grounded code review for Python.** RefactorLens computes
54
+ object-oriented design metrics from your codebase and reports them as evidence
55
+ — not opinions.
56
+
57
+ ```bash
58
+ pipx install refactorlens
59
+ rlens scan .
60
+ ```
61
+
62
+ ```
63
+ your-project/src — 12 modules, 14 classes, 68 functions
64
+
65
+ Class metrics
66
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━┳━━━━━━━┳━━━━━┳━━━━━━┳━━━━━━┓
67
+ ┃ Class ┃ NOM ┃ WMC ┃ LCOM4 ┃ DCC ┃ DAM ┃ CAM ┃
68
+ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━╇━━━━━╇━━━━━━━╇━━━━━╇━━━━━━╇━━━━━━┩
69
+ │ orders:OrderManager │ 25 │ 49 │ 4 │ 8 │ 1.00 │ — │
70
+ │ reporting:ReportBuilder │ 6 │ 7 │ 2 │ 0 │ 1.00 │ — │
71
+ │ models:Customer │ 6 │ 6 │ 3 │ 0 │ 0.20 │ 1.00 │
72
+ └─────────────────────────────┴─────┴─────┴───────┴─────┴──────┴──────┘
73
+
74
+ — CAM not computed for 2 classes (no annotated parameters)
75
+ 8 items over threshold.
76
+ ```
77
+
78
+ > **Status: v0.1.0.** `scan` is complete and tested. The AI advisor (`advise`)
79
+ > and the verification loop (`verify`) are the next milestones — see
80
+ > [Roadmap](#roadmap).
81
+
82
+ ## Why this exists
83
+
84
+ Most "let an AI review my code" tools hand the model raw source and hope for the
85
+ best. RefactorLens is built on a different bet: **give the model measurements,
86
+ then check its work.**
87
+
88
+ Two layers make that concrete.
89
+
90
+ **Metric-grounded prompting.** Before asking a model for advice, compute the
91
+ numbers. A suggestion that says "this class has four disjoint responsibilities
92
+ (LCOM4 = 4) and touches eight other classes (DCC = 8)" is checkable. A
93
+ suggestion that says "this feels messy" is not.
94
+
95
+ **The verify loop.** Every suggestion must come with a *measurable prediction* —
96
+ "this change lowers LCOM4 and leaves DCC unchanged". After the change is
97
+ applied, the metrics are recomputed and two questions get answered at once: did
98
+ quality actually improve, and **was the model's own prediction correct?**
99
+
100
+ The second question is the interesting one.
101
+
102
+ ## Install
103
+
104
+ ```bash
105
+ pipx install refactorlens # recommended: isolated environment
106
+ pip install refactorlens # or into your current environment
107
+ ```
108
+
109
+ Requires Python 3.11 or newer. RefactorLens is a CLI tool rather than a library,
110
+ so `pipx` is the better fit.
111
+
112
+ ## Usage
113
+
114
+ ```bash
115
+ rlens scan . # scan the current project
116
+ rlens scan src/ --no-report # print tables only, write nothing
117
+ rlens scan . --fail-on-violation # exit 1 if anything is over threshold
118
+ rlens --version
119
+ ```
120
+
121
+ `scan` prints two tables and writes a JSON report to `reports/`:
122
+
123
+ - **Class metrics** — every class, worst first
124
+ - **Functions over threshold** — only the ones that exceed a limit, because
125
+ printing every function makes the output useless
126
+
127
+ Values shown as `—` were **not computed**, which is different from zero. The
128
+ footnote below the table says why.
129
+
130
+ ### Exit codes
131
+
132
+ | Code | Meaning |
133
+ |---|---|
134
+ | 0 | Success |
135
+ | 1 | Config error, unwritable report, or `--fail-on-violation` triggered |
136
+ | 2 | Invalid command usage |
137
+
138
+ ## Configuration
139
+
140
+ RefactorLens works with no configuration. To customise, put `rlens.yaml` in your
141
+ project root — it is searched for upward from the scanned path.
142
+
143
+ ```yaml
144
+ scan:
145
+ include: ["."] # scan everything under the given path
146
+ exclude: ["tests/", ".venv/", "migrations/"]
147
+ output_dir: reports/
148
+
149
+ metrics:
150
+ cam_min_annotation_coverage: 0.7 # below this, CAM reports null
151
+
152
+ thresholds:
153
+ cyclomatic_complexity: {warn: 10, critical: 20}
154
+ max_params: {warn: 5}
155
+ max_nesting: {warn: 4}
156
+ lcom4: {warn: 2, critical: 4}
157
+ dcc: {warn: 7}
158
+ wmc: {warn: 50}
159
+ nom: {warn: 20}
160
+ ```
161
+
162
+ Unknown keys are an **error**, not a warning. A typo like `max_nestings` would
163
+ otherwise leave you silently running on defaults.
164
+
165
+ ## Metric definitions and adaptations
166
+
167
+ The metrics are inspired by the QMOOD family and classic complexity measures.
168
+ **Only a subset of QMOOD is implemented; this is not a complete QMOOD tool.**
169
+
170
+ Python is dynamically typed, so several object-oriented metrics can only be
171
+ computed by adaptation. Those adaptations are documented here rather than
172
+ hidden.
173
+
174
+ ### Shared rule: which methods count
175
+
176
+ All six class metrics operate on the same method set: methods defined directly
177
+ in the class body, excluding dunder methods. `@property`, `@staticmethod` and
178
+ `@classmethod` are included. Nested functions and nested classes are not.
179
+
180
+ `__init__` is excluded, and this matters most for LCOM4: a constructor touches
181
+ every attribute by definition, so counting it would merge every class into a
182
+ single component and make the metric useless. Classic LCOM4 excludes
183
+ constructors for the same reason.
184
+
185
+ ### Class-level metrics
186
+
187
+ | Metric | What it counts | Adaptation |
188
+ |---|---|---|
189
+ | **NOM** | Methods in the class | Dunders excluded |
190
+ | **WMC** | Sum of cyclomatic complexity over those methods | Same method set as NOM, for consistency |
191
+ | **LCOM4** | Connected components in the method–attribute graph | See limitation below |
192
+ | **DAM** | Ratio of private attributes | Reported twice: `dam` counts `_x` and `__x`; `dam_strict` counts only `__x` |
193
+ | **DCC** | Distinct project-internal classes referenced | Name-based resolution; see below |
194
+ | **CAM** | Mean ratio of each method's parameter types to the class-wide set | Computed only when annotation coverage is sufficient |
195
+
196
+ **Attribute set (used by DAM and LCOM4)** is the union of: class-level
197
+ assignments and annotations, `self.x = ...` in *any* method (not just
198
+ `__init__`), and names listed in `__slots__`. Names that are only ever read are
199
+ not attributes.
200
+
201
+ **DCC resolution is best-effort.** Python has no static type information, so a
202
+ name appearing in a class body is counted as a reference if it matches a class
203
+ defined anywhere in the project. A local variable that shares a name with a
204
+ class will be counted. Standard-library and third-party classes are not counted.
205
+
206
+ **CAM is conditional.** The classic definition uses parameter *types*. Parameter
207
+ *names* measure something else entirely and would make the result incomparable
208
+ to the literature, so name similarity is never used as a fallback. Most Python
209
+ codebases are unannotated; forcing a number out of them would feed the model
210
+ noise dressed up as evidence. If annotation coverage falls below
211
+ `metrics.cam_min_annotation_coverage` (default 0.7), CAM reports `null` and the
212
+ report records why.
213
+
214
+ ### Known limitation: LCOM4 and data classes
215
+
216
+ LCOM4 flags well-written data-holder classes as uncohesive. A class with one
217
+ accessor per field — `rename` touching `name`, `promote` touching `tier` — has
218
+ methods that share no state, so LCOM4 counts them as separate responsibilities.
219
+
220
+ This is a property of the metric, not a bug, and it is well documented in the
221
+ literature. RefactorLens reports the number as measured rather than
222
+ special-casing it away. When reading a report, treat a high LCOM4 on a small
223
+ class as a question rather than a verdict; **WMC and DCC separate genuinely
224
+ overloaded classes from plain data holders far more reliably.**
225
+
226
+ ### Function-level metrics
227
+
228
+ Cyclomatic complexity counts `if`/`elif`, loops, `except` handlers, ternaries,
229
+ each additional `and`/`or` operand, comprehension clauses, and `match` cases.
230
+ `else`, `with`, and `try` itself add nothing — they do not branch execution.
231
+
232
+ Nesting depth treats `elif` chains as flat: a ten-branch `elif` is not ten
233
+ levels deep.
234
+
235
+ Nested function definitions are never entered. A function containing a closure
236
+ does not inherit the closure's complexity.
237
+
238
+ ## What RefactorLens does not do
239
+
240
+ - **It does not run your code.** Files are parsed with `ast`, never executed.
241
+ - **It does not fix anything.** `scan` measures; future versions will suggest.
242
+ - **It does not send anything anywhere.** `scan` is entirely local. When
243
+ `advise` arrives, it will send selected code to whichever LLM provider you
244
+ configure, and local execution via Ollama will be supported for sensitive
245
+ codebases.
246
+ - **Python only.** No Java or C#.
247
+
248
+ ## Roadmap
249
+
250
+ | Phase | Contents | Version |
251
+ |---|---|---|
252
+ | 0 | Package skeleton, config, test foundation | — |
253
+ | 1 | Metric engine (`scan`) | — |
254
+ | **2** | **PyPI release** | **v0.1.0** |
255
+ | 3 | AI advisor (`advise`) | v0.2.0 |
256
+ | 4 | Verification loop (`verify`) | v0.3.0 |
257
+ | 5 | Experiment and findings | v1.0.0 |
258
+
259
+ Ideas deliberately out of scope live in [FUTURE.md](FUTURE.md).
260
+
261
+ ## Development
262
+
263
+ ```bash
264
+ git clone https://github.com/okngms/refactorlens
265
+ cd refactorlens
266
+ python -m venv .venv && source .venv/bin/activate
267
+ pip install -e ".[dev]"
268
+
269
+ pytest tests # the package's own tests
270
+ pytest examples/messy_project/tests # the fixture's behaviour tests
271
+ ruff check . && ruff format --check .
272
+ ```
273
+
274
+ `examples/messy_project` is a deliberately badly designed sample project used as
275
+ the test fixture; every metric is verified against hand-computed gold values on
276
+ it. See [SMELLS.md](examples/messy_project/SMELLS.md) for the inventory of
277
+ intentional smells and the reasoning behind each.
278
+
279
+ Its behaviour test suite exists for a specific reason: from phase 4 onward,
280
+ refactoring suggestions get applied by hand. If a refactoring breaks the code,
281
+ the metrics improve while the program stops working. The rule is therefore
282
+ absolute — **no metric delta counts unless the behaviour tests pass.**
283
+
284
+ ## Licence
285
+
286
+ MIT
@@ -0,0 +1,17 @@
1
+ rlens/__init__.py,sha256=q2iF4jX1kqM0qJAJBTSfjhQ1v4IEszdZu5kEywer4Fw,194
2
+ rlens/cli.py,sha256=aVmIf34GgOIW9QiGCnNT1f9EDzvorIDbjf-YHRniZtc,4184
3
+ rlens/config.py,sha256=2YATGnxPdo8BA-zk50HO523Bydvv29WfX4tDqMvTAio,11794
4
+ rlens/analysis/__init__.py,sha256=f-92u1n4r4f6HxSmeP01aYiEzAZoC_lfZcjM-KqLYog,36
5
+ rlens/analysis/class_metrics.py,sha256=9osH474vi1t8CCq98zSJw8Sw5-YlaAmkiYEX9VzlFqg,17433
6
+ rlens/analysis/func_metrics.py,sha256=KQRaATWjLm5hkmfjgauviz109EkvVSzW45RGei-UYXo,9113
7
+ rlens/analysis/model.py,sha256=QKs07-0hoVLD8lTzvF255SOs1dd5lRQyU0NxETQTAI0,2820
8
+ rlens/analysis/parser.py,sha256=rko9JvWUXV-uDKupKoLWy0z7SrGKu7qsrkvc-LXwd7w,6839
9
+ rlens/analysis/scanner.py,sha256=B8k4niNcjscM831YdYcIZSxEP1ntIdIMAser-wyBEzo,3321
10
+ rlens/report/__init__.py,sha256=_w7dcZZkJ_Rj3dXaLNNuShi-2NauC2pRKViPZBGMaiE,67
11
+ rlens/report/files.py,sha256=2oYw5KfYOGtDvTHxc2T3VnP-XgWszIOU7IAG0MobgeU,3539
12
+ rlens/report/terminal.py,sha256=18i5a12xLQc1EHLHxJ6741SE6sQejFPskcm6CwoxSb8,9166
13
+ refactorlens-0.1.0.dist-info/METADATA,sha256=6WS5KfYbrIOD3J6jHa0epPfmp9R8MwQTzhWuVHHSqDM,12164
14
+ refactorlens-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
15
+ refactorlens-0.1.0.dist-info/entry_points.txt,sha256=eQslxVYw-TZjtlAE1Y8NVEtsoiNzBt4dQF9qQVR3jzY,41
16
+ refactorlens-0.1.0.dist-info/licenses/LICENSE,sha256=27yMVc5Pbh6-0Xa0SKWmTyRxjdflEBCdY47Evihns9I,1082
17
+ refactorlens-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ rlens = rlens.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 RefactorLens contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
rlens/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ """RefactorLens — metric-grounded AI code review CLI.
2
+
3
+ Paket sürümü burada tek kaynaktan tanımlanır; pyproject.toml bu değeri okur.
4
+ """
5
+
6
+ __version__ = "0.1.0"
7
+
8
+ __all__ = ["__version__"]
@@ -0,0 +1 @@
1
+ """RefactorLens analysis paketi."""