gitmole 0.6.8__tar.gz → 0.6.9__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.
- {gitmole-0.6.8 → gitmole-0.6.9}/PKG-INFO +1 -1
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/__init__.py +1 -1
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/functions.py +12 -2
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/load.py +10 -1
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole.egg-info/PKG-INFO +1 -1
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_functions.py +11 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_load.py +13 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/LICENSE +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/README.md +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/__main__.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/backtest.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/banner.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/blame.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/clean.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/cli.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/coupling.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/filetypes.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/findings.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/hotspots.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/identity.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/knowledge.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/leaks.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/loss.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/maat.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/render.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/run.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/textfmt.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/trend.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole/watch.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole.egg-info/SOURCES.txt +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole.egg-info/dependency_links.txt +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole.egg-info/entry_points.txt +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole.egg-info/requires.txt +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/gitmole.egg-info/top_level.txt +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/pyproject.toml +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/setup.cfg +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_backtest.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_banner.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_blame.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_clean.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_cli.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_coupling.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_filetypes.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_findings.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_golden.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_hotspots.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_identity.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_knowledge.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_leaks.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_loss.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_maat.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_packaging.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_render.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_run.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_textfmt.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_trend.py +0 -0
- {gitmole-0.6.8 → gitmole-0.6.9}/tests/test_watch.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitmole
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.9
|
|
4
4
|
Summary: Offline git repository analysis with a terminal report: hotspots, coupling, ownership, code age, secrets, repo health.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/antvinni/gitmole
|
|
@@ -30,10 +30,20 @@ def select_files(repo: str, ignore=(), types_spec: str = None) -> list:
|
|
|
30
30
|
return [f for f in files if lizard.get_reader_for(f) is not None]
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
NAME_CAP = 200 # a deeply nested fixture gives lizard a dotted name of megabytes; nobody reads past this
|
|
34
|
+
LONG_NAME_CAP = 500
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _cut(text: str, cap: int) -> str:
|
|
38
|
+
return text if len(text) <= cap else text[:cap - 1] + "…"
|
|
39
|
+
|
|
40
|
+
|
|
33
41
|
def csv_row(info, fn) -> list:
|
|
34
|
-
"""The columns `lizard --csv` prints, so the loader does not care which produced the file.
|
|
42
|
+
"""The columns `lizard --csv` prints, so the loader does not care which produced the file. Names
|
|
43
|
+
are cut to what a table can show, so one pathological fixture cannot make the file unreadable."""
|
|
44
|
+
name = _cut(fn.name, NAME_CAP)
|
|
35
45
|
return [fn.nloc, fn.cyclomatic_complexity, fn.token_count, fn.parameter_count, fn.length,
|
|
36
|
-
f"{
|
|
46
|
+
f"{name}@{fn.start_line}-{fn.end_line}@{info.filename}", info.filename, name, _cut(fn.long_name, LONG_NAME_CAP), fn.start_line, fn.end_line]
|
|
37
47
|
|
|
38
48
|
|
|
39
49
|
def write_duplicates(dup: Duplicates, fh) -> None:
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
|
|
4
4
|
import csv
|
|
5
5
|
import io
|
|
6
|
+
import sys
|
|
6
7
|
import json
|
|
7
8
|
import os
|
|
8
9
|
import re
|
|
@@ -145,13 +146,21 @@ def parse_authors_log(text: str) -> list:
|
|
|
145
146
|
]
|
|
146
147
|
|
|
147
148
|
|
|
149
|
+
NAME_CAP = 200 # a function name a table can show; deeply nested fixtures give lizard dotted names of megabytes
|
|
150
|
+
csv.field_size_limit(min(sys.maxsize, 2**31 - 1)) # an older functions.csv may still carry such a name
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _cut(name: str, cap: int = NAME_CAP) -> str:
|
|
154
|
+
return name if len(name) <= cap else name[:cap - 1] + "…"
|
|
155
|
+
|
|
156
|
+
|
|
148
157
|
def parse_functions(text: str) -> list:
|
|
149
158
|
"""lizard --csv rows: nloc, ccn, tokens, params, length, location, file, function, long name, start, end."""
|
|
150
159
|
rows = []
|
|
151
160
|
for r in csv.reader(io.StringIO(text)):
|
|
152
161
|
if len(r) < 11:
|
|
153
162
|
continue
|
|
154
|
-
rows.append({"file": _rel(r[6]), "function": r[7] or "(anonymous)", "ccn": _num(r[1]), "nloc": _num(r[0]), "params": _num(r[3]),
|
|
163
|
+
rows.append({"file": _rel(r[6]), "function": _cut(r[7]) or "(anonymous)", "ccn": _num(r[1]), "nloc": _num(r[0]), "params": _num(r[3]),
|
|
155
164
|
"start": _num(r[9]), "end": _num(r[10])})
|
|
156
165
|
return rows
|
|
157
166
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitmole
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.9
|
|
4
4
|
Summary: Offline git repository analysis with a terminal report: hotspots, coupling, ownership, code age, secrets, repo health.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/antvinni/gitmole
|
|
@@ -67,6 +67,17 @@ class FunctionsScript(unittest.TestCase):
|
|
|
67
67
|
self.assertIn('"tracked"', csv, "functions are still measured")
|
|
68
68
|
self.assertIsNone(dup, "no duplicates.txt: the finder did not run, so nothing pretends it did")
|
|
69
69
|
|
|
70
|
+
def test_a_huge_nested_name_is_cut_before_it_is_written(self):
|
|
71
|
+
from types import SimpleNamespace
|
|
72
|
+
name = ".".join("a" for _ in range(100_000))
|
|
73
|
+
fn = SimpleNamespace(nloc=5, cyclomatic_complexity=3, token_count=40, parameter_count=1, length=5, name=name,
|
|
74
|
+
long_name=name + "( )", start_line=1, end_line=5)
|
|
75
|
+
row = functions.csv_row(SimpleNamespace(filename="a.py"), fn)
|
|
76
|
+
self.assertEqual(len(row[7]), functions.NAME_CAP)
|
|
77
|
+
self.assertTrue(row[7].endswith("…"))
|
|
78
|
+
self.assertLessEqual(len(row[8]), functions.LONG_NAME_CAP)
|
|
79
|
+
self.assertLessEqual(len(row[5]), functions.NAME_CAP + len("@1-5@a.py"))
|
|
80
|
+
|
|
70
81
|
def test_csv_matches_lizards_own_layout(self):
|
|
71
82
|
with tempfile.TemporaryDirectory() as d:
|
|
72
83
|
make_repo(d)
|
|
@@ -138,6 +138,19 @@ class ParseFunctions(unittest.TestCase):
|
|
|
138
138
|
def test_empty(self):
|
|
139
139
|
self.assertEqual(load.parse_functions(""), [])
|
|
140
140
|
|
|
141
|
+
def test_a_row_with_a_huge_long_name_does_not_abort_the_report(self):
|
|
142
|
+
# ruff: lizard wrote a long name of several hundred kilobytes for one function, over csv's default field limit
|
|
143
|
+
huge = "f( " + "a, " * 100_000 + ")"
|
|
144
|
+
rows = load.parse_functions(f'5,3,40,1,5,"f@1-5@a.rs","a.rs","f","{huge}",1,5\n')
|
|
145
|
+
self.assertEqual((rows[0]["function"], rows[0]["file"], rows[0]["ccn"]), ("f", "a.rs", 3))
|
|
146
|
+
|
|
147
|
+
def test_a_huge_function_name_is_cut_to_something_a_table_can_show(self):
|
|
148
|
+
# a test fixture of deeply nested functions gives lizard a dotted name of megabytes
|
|
149
|
+
name = ".".join("a" for _ in range(100_000))
|
|
150
|
+
rows = load.parse_functions(f'5,3,40,1,5,"{name}@1-5@a.py","a.py","{name}","{name}( )",1,5\n')
|
|
151
|
+
self.assertEqual(len(rows[0]["function"]), load.NAME_CAP)
|
|
152
|
+
self.assertTrue(rows[0]["function"].endswith("…"))
|
|
153
|
+
|
|
141
154
|
def test_a_nameless_function_is_called_anonymous(self):
|
|
142
155
|
# lizard names Go function literals with an empty string where it names JavaScript's "(anonymous)"
|
|
143
156
|
rows = load.parse_functions('136,47,926,1,270,"@316-585@completions.go","completions.go",""," c * Command",316,585\n')
|
|
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
|