repoglance 0.4.2__tar.gz → 0.4.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.
- {repoglance-0.4.2 → repoglance-0.4.3}/CHANGELOG.md +14 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/PKG-INFO +11 -6
- {repoglance-0.4.2 → repoglance-0.4.3}/README.md +10 -5
- {repoglance-0.4.2 → repoglance-0.4.3}/pyproject.toml +1 -1
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/__init__.py +1 -1
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/cli.py +5 -4
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/complexity.py +22 -7
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/scanner.py +19 -9
- {repoglance-0.4.2 → repoglance-0.4.3}/tests/test_v041.py +14 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.github/workflows/ci.yml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.github/workflows/release.yml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.github/workflows/repoglance.yml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.gitignore +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.pre-commit-hooks.yaml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/.repoglance-badge.json +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/CODE_OF_CONDUCT.md +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/CONTRIBUTING.md +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/Dockerfile +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/LICENSE +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/RELEASING.md +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/SECURITY.md +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/action.yml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/assets/badge.svg +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/assets/demo.svg +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/assets/demo.tape +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/assets/showcase/flask.svg +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/assets/showcase/httpie.svg +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/assets/showcase/requests.svg +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/benchmarks/bench.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/docs/index.md +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/editors/vscode/README.md +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/editors/vscode/extension.js +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/editors/vscode/package.json +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/integrations/gitlab-ci.yml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/mkdocs.yml +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/packaging/homebrew/repoglance.rb +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/__main__.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/badge.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/cache.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/config.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/dedup.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/gitinfo.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/languages.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/metrics.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/plugins.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/report.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/src/repoglance/vendored.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/tests/test_cli.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/tests/test_complexity.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/tests/test_features.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/tests/test_scanner.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/tests/test_scanner_extra.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/tests/test_v030.py +0 -0
- {repoglance-0.4.2 → repoglance-0.4.3}/tests/test_v040.py +0 -0
|
@@ -4,6 +4,20 @@ All notable changes to this project are documented here. The format is based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.4.3] - 2026-08-01
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **`--fast` mode**: counts only (languages, LOC, sizes), skipping per-function
|
|
11
|
+
complexity parsing — the expensive step. Combined with the process pool this
|
|
12
|
+
scans **20 million lines in ~4.4 s** (~4.5M LOC/s). Use it for size/inventory
|
|
13
|
+
passes on very large monorepos; drop it for full complexity/health analysis.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **Python complexity now uses CPython's C-accelerated `ast`** instead of the
|
|
17
|
+
pure-Python tokenizer, roughly **halving full-analysis time on Python-heavy
|
|
18
|
+
repos** (Django 415k LOC: ~10 s → ~5 s on 8 cores). Other languages still use
|
|
19
|
+
lizard. Adaptive process-pool chunk sizing reduces IPC overhead.
|
|
20
|
+
|
|
7
21
|
## [0.4.2] - 2026-08-01
|
|
8
22
|
|
|
9
23
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: repoglance
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Instant, gorgeous insight into any code repository — languages, complexity hotspots, TODOs and git activity in one terminal command.
|
|
5
5
|
Project-URL: Homepage, https://github.com/SRJ-ai/repoglance
|
|
6
6
|
Project-URL: Repository, https://github.com/SRJ-ai/repoglance
|
|
@@ -302,11 +302,16 @@ millions of lines, thousands of files — not just small projects:
|
|
|
302
302
|
|
|
303
303
|
Measured on Django (3,180 files, ~415k lines of code), single machine:
|
|
304
304
|
|
|
305
|
-
| Run | Time |
|
|
306
|
-
|
|
307
|
-
| Cold scan,
|
|
308
|
-
|
|
|
309
|
-
|
|
|
305
|
+
| Run | Repo | Time |
|
|
306
|
+
|---|---|--:|
|
|
307
|
+
| Cold scan, full analysis (8 cores) | Django, 415k LOC | ~5.0 s |
|
|
308
|
+
| Re-run with `--cache` | Django, 415k LOC | ~1.1 s |
|
|
309
|
+
| **`--fast` (counts only), process pool** | **20,000,000 LOC** | **~4.4 s** |
|
|
310
|
+
|
|
311
|
+
`--fast` skips per-function complexity parsing (the expensive step) and reports
|
|
312
|
+
languages, line counts and sizes only — that's what makes a 20-million-line
|
|
313
|
+
scan finish in seconds (~4.5M LOC/s here). Drop `--fast` when you want the full
|
|
314
|
+
complexity/health analysis.
|
|
310
315
|
|
|
311
316
|
The cold scan is dominated by real per-function complexity parsing. The process
|
|
312
317
|
pool spreads that across cores (~2× here); the incremental cache (`--cache
|
|
@@ -270,11 +270,16 @@ millions of lines, thousands of files — not just small projects:
|
|
|
270
270
|
|
|
271
271
|
Measured on Django (3,180 files, ~415k lines of code), single machine:
|
|
272
272
|
|
|
273
|
-
| Run | Time |
|
|
274
|
-
|
|
275
|
-
| Cold scan,
|
|
276
|
-
|
|
|
277
|
-
|
|
|
273
|
+
| Run | Repo | Time |
|
|
274
|
+
|---|---|--:|
|
|
275
|
+
| Cold scan, full analysis (8 cores) | Django, 415k LOC | ~5.0 s |
|
|
276
|
+
| Re-run with `--cache` | Django, 415k LOC | ~1.1 s |
|
|
277
|
+
| **`--fast` (counts only), process pool** | **20,000,000 LOC** | **~4.4 s** |
|
|
278
|
+
|
|
279
|
+
`--fast` skips per-function complexity parsing (the expensive step) and reports
|
|
280
|
+
languages, line counts and sizes only — that's what makes a 20-million-line
|
|
281
|
+
scan finish in seconds (~4.5M LOC/s here). Drop `--fast` when you want the full
|
|
282
|
+
complexity/health analysis.
|
|
278
283
|
|
|
279
284
|
The cold scan is dominated by real per-function complexity parsing. The process
|
|
280
285
|
pool spreads that across cores (~2× here); the incremental cache (`--cache
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "repoglance"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.3"
|
|
8
8
|
description = "Instant, gorgeous insight into any code repository — languages, complexity hotspots, TODOs and git activity in one terminal command."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -41,6 +41,7 @@ def _resolve(cli_val, cfg, key, default):
|
|
|
41
41
|
@click.option("--max-bytes", type=int, default=None, help="Skip files larger than this many bytes.")
|
|
42
42
|
@click.option("--jobs", type=int, default=None, help="Number of parallel workers for scanning.")
|
|
43
43
|
@click.option("--processes/--threads", "use_processes", default=None, help="Force process- or thread-based parallelism (default: auto by repo size).")
|
|
44
|
+
@click.option("--fast", is_flag=True, help="Counts only (languages, LOC) — skip complexity parsing for maximum speed on huge repos.")
|
|
44
45
|
@click.option("--duplicates", "want_dupes", is_flag=True, help="Detect duplicated code blocks.")
|
|
45
46
|
@click.option("--owners", "want_owners", is_flag=True, help="Attribute top complexity hotspots to authors (git blame).")
|
|
46
47
|
@click.option("--include-vendored", is_flag=True, help="Analyze vendored/generated files instead of excluding them.")
|
|
@@ -57,9 +58,9 @@ def _resolve(cli_val, cfg, key, default):
|
|
|
57
58
|
@click.version_option(__version__, "-V", "--version", prog_name="repoglance")
|
|
58
59
|
def main(path, as_json, as_md, as_csv, as_sarif, sarif_threshold, html_path, svg_path,
|
|
59
60
|
badge_path, badge_json_path, baseline_out, since_rev, include, exclude, ignore,
|
|
60
|
-
no_git, max_bytes, jobs, use_processes, want_dupes, want_owners,
|
|
61
|
-
cache_path, watch, compare_to, fail_on_regression, ci,
|
|
62
|
-
fail_under):
|
|
61
|
+
no_git, max_bytes, jobs, use_processes, fast, want_dupes, want_owners,
|
|
62
|
+
include_vendored, cache_path, watch, compare_to, fail_on_regression, ci,
|
|
63
|
+
max_complexity, max_todos, fail_under):
|
|
63
64
|
"""Instant, gorgeous insight into any code repository.
|
|
64
65
|
|
|
65
66
|
PATH defaults to the current directory. Configuration may be supplied via
|
|
@@ -82,7 +83,7 @@ def main(path, as_json, as_md, as_csv, as_sarif, sarif_threshold, html_path, svg
|
|
|
82
83
|
"max_bytes": max_bytes, "extra_ignores": ignores, "include": include,
|
|
83
84
|
"exclude": exclude, "changed_only": changed, "jobs": jobs,
|
|
84
85
|
"include_vendored": include_vendored, "keep_contents": want_dupes,
|
|
85
|
-
"processes": use_processes,
|
|
86
|
+
"processes": use_processes, "fast": fast,
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
if watch:
|
|
@@ -70,7 +70,7 @@ def _lizard_scores(source: str, rel_path: str) -> Optional[List[FuncScore]]:
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
def python_complexity(source: str, rel_path: str) -> List[FuncScore]:
|
|
73
|
-
"""AST-based
|
|
73
|
+
"""Fast AST-based complexity for Python (CPython's C parser)."""
|
|
74
74
|
try:
|
|
75
75
|
tree = ast.parse(source)
|
|
76
76
|
except SyntaxError:
|
|
@@ -79,17 +79,24 @@ def python_complexity(source: str, rel_path: str) -> List[FuncScore]:
|
|
|
79
79
|
scores: List[FuncScore] = []
|
|
80
80
|
|
|
81
81
|
class Visitor(ast.NodeVisitor):
|
|
82
|
-
def
|
|
82
|
+
def _measure(self, node):
|
|
83
83
|
complexity = 1
|
|
84
|
+
nodes = 0
|
|
84
85
|
for child in ast.walk(node):
|
|
86
|
+
nodes += 1
|
|
85
87
|
if isinstance(child, _BRANCH_NODES):
|
|
86
88
|
complexity += 1
|
|
87
89
|
elif isinstance(child, _BOOLOP_EXTRA):
|
|
88
90
|
complexity += len(child.values) - 1
|
|
89
|
-
|
|
91
|
+
end = getattr(node, "end_lineno", node.lineno) or node.lineno
|
|
92
|
+
nloc = max(1, end - node.lineno + 1)
|
|
93
|
+
args = node.args
|
|
94
|
+
params = len(args.args) + len(getattr(args, "posonlyargs", [])) + len(args.kwonlyargs)
|
|
95
|
+
return complexity, nloc, nodes, params
|
|
90
96
|
|
|
91
97
|
def visit_FunctionDef(self, node):
|
|
92
|
-
|
|
98
|
+
cx, nloc, tokens, params = self._measure(node)
|
|
99
|
+
scores.append(FuncScore(rel_path, node.name, node.lineno, cx, nloc, tokens, params))
|
|
93
100
|
self.generic_visit(node)
|
|
94
101
|
|
|
95
102
|
visit_AsyncFunctionDef = visit_FunctionDef
|
|
@@ -104,14 +111,22 @@ def heuristic_complexity(source: str, rel_path: str) -> int:
|
|
|
104
111
|
|
|
105
112
|
|
|
106
113
|
def analyze_complexity(source: str, rel_path: str, language: str) -> List[FuncScore]:
|
|
107
|
-
"""Return per-function complexity
|
|
114
|
+
"""Return per-function complexity.
|
|
115
|
+
|
|
116
|
+
Python is analyzed with CPython's C-accelerated ``ast`` (much faster than a
|
|
117
|
+
pure-Python tokenizer), which matters a lot on Python-heavy monorepos. Other
|
|
118
|
+
languages use lizard; anything lizard cannot read falls back to a heuristic.
|
|
119
|
+
"""
|
|
108
120
|
if language in NON_CODE_LANGS:
|
|
109
121
|
return []
|
|
122
|
+
if language == "Python":
|
|
123
|
+
scores = python_complexity(source, rel_path)
|
|
124
|
+
if scores:
|
|
125
|
+
return scores
|
|
126
|
+
# Empty may mean a syntax error (e.g. Python 2); let lizard try.
|
|
110
127
|
scores = _lizard_scores(source, rel_path)
|
|
111
128
|
if scores is not None:
|
|
112
129
|
return scores
|
|
113
|
-
if language == "Python":
|
|
114
|
-
return python_complexity(source, rel_path)
|
|
115
130
|
score = heuristic_complexity(source, rel_path)
|
|
116
131
|
return [FuncScore(rel_path, "(file)", 1, score)] if score > 1 else []
|
|
117
132
|
|
|
@@ -18,7 +18,7 @@ from typing import Dict, Iterable, List, Optional
|
|
|
18
18
|
|
|
19
19
|
from .complexity import FuncScore, analyze_complexity
|
|
20
20
|
from .languages import lang_for
|
|
21
|
-
from .vendored import is_vendored
|
|
21
|
+
from .vendored import is_vendored, is_vendored_path
|
|
22
22
|
|
|
23
23
|
# Above this many files we default to process-based parallelism: complexity
|
|
24
24
|
# parsing is CPU-bound and the GIL prevents threads from using multiple cores.
|
|
@@ -204,6 +204,7 @@ def scan(
|
|
|
204
204
|
keep_contents: bool = False,
|
|
205
205
|
cache_data: Optional[dict] = None,
|
|
206
206
|
processes: Optional[bool] = None,
|
|
207
|
+
fast: bool = False,
|
|
207
208
|
) -> ScanResult:
|
|
208
209
|
"""Walk ``root`` and gather per-file line/language/complexity stats.
|
|
209
210
|
|
|
@@ -250,7 +251,7 @@ def scan(
|
|
|
250
251
|
else:
|
|
251
252
|
to_parse = todo
|
|
252
253
|
|
|
253
|
-
processed = _parallel_process(to_parse, root_path, max_bytes, keep_contents, jobs, processes)
|
|
254
|
+
processed = _parallel_process(to_parse, root_path, max_bytes, keep_contents, jobs, processes, fast)
|
|
254
255
|
|
|
255
256
|
for full, item in zip(to_parse, processed):
|
|
256
257
|
if item is None:
|
|
@@ -303,14 +304,15 @@ def _absorb(result, stat, todos, scores, vendored, include_vendored, text, keep_
|
|
|
303
304
|
result.contents[stat.path] = text
|
|
304
305
|
|
|
305
306
|
|
|
306
|
-
def _parallel_process(to_parse, root_path, max_bytes, keep_contents, jobs, processes):
|
|
307
|
+
def _parallel_process(to_parse, root_path, max_bytes, keep_contents, jobs, processes, fast=False):
|
|
307
308
|
"""Analyze files in parallel. Uses processes for large, CPU-bound scans so
|
|
308
309
|
complexity parsing actually spreads across cores (threads can't, due to the
|
|
309
310
|
GIL); falls back to threads for small scans or when contents must be kept."""
|
|
310
311
|
if not to_parse:
|
|
311
312
|
return []
|
|
312
313
|
worker = functools.partial(
|
|
313
|
-
_process_file, root_path=root_path, max_bytes=max_bytes,
|
|
314
|
+
_process_file, root_path=root_path, max_bytes=max_bytes,
|
|
315
|
+
keep_contents=keep_contents, fast=fast,
|
|
314
316
|
)
|
|
315
317
|
use_proc = processes if processes is not None else (
|
|
316
318
|
not keep_contents and len(to_parse) >= _PROCESS_THRESHOLD and (os.cpu_count() or 1) > 1
|
|
@@ -318,8 +320,10 @@ def _parallel_process(to_parse, root_path, max_bytes, keep_contents, jobs, proce
|
|
|
318
320
|
if use_proc:
|
|
319
321
|
try:
|
|
320
322
|
workers = jobs or min(8, os.cpu_count() or 2)
|
|
323
|
+
# Larger chunks amortize per-task IPC/pickling overhead.
|
|
324
|
+
chunk = max(16, len(to_parse) // (workers * 4))
|
|
321
325
|
with ProcessPoolExecutor(max_workers=workers) as pool:
|
|
322
|
-
return list(pool.map(worker, to_parse, chunksize=
|
|
326
|
+
return list(pool.map(worker, to_parse, chunksize=chunk))
|
|
323
327
|
except Exception:
|
|
324
328
|
pass # fall back to threads if the process pool cannot start
|
|
325
329
|
workers = jobs or min(32, (os.cpu_count() or 4) * 4)
|
|
@@ -327,9 +331,15 @@ def _parallel_process(to_parse, root_path, max_bytes, keep_contents, jobs, proce
|
|
|
327
331
|
return list(pool.map(worker, to_parse))
|
|
328
332
|
|
|
329
333
|
|
|
330
|
-
def _process_file(full: Path, root_path: Path, max_bytes: int,
|
|
334
|
+
def _process_file(full: Path, root_path: Path, max_bytes: int,
|
|
335
|
+
keep_contents: bool = False, fast: bool = False):
|
|
331
336
|
"""Read and analyze one file. Returns (FileStat, todos, scores, text, vendored)
|
|
332
|
-
or None. Top-level and picklable so it works with a process pool.
|
|
337
|
+
or None. Top-level and picklable so it works with a process pool.
|
|
338
|
+
|
|
339
|
+
In ``fast`` mode we only count lines and detect language/vendoring — the
|
|
340
|
+
per-function complexity parse (the expensive step) is skipped, which is what
|
|
341
|
+
lets very large repositories be scanned in seconds.
|
|
342
|
+
"""
|
|
333
343
|
fn = full.name
|
|
334
344
|
ext = fn.rsplit(".", 1)[-1] if "." in fn else ""
|
|
335
345
|
language = lang_for(ext, fn)
|
|
@@ -344,10 +354,10 @@ def _process_file(full: Path, root_path: Path, max_bytes: int, keep_contents: bo
|
|
|
344
354
|
rel = full.relative_to(root_path).as_posix()
|
|
345
355
|
total, code, blank, comment = _count_lines(text, language)
|
|
346
356
|
stat = FileStat(rel, language, total, code, blank, comment, size)
|
|
347
|
-
vendored = is_vendored(rel, text)
|
|
357
|
+
vendored = is_vendored_path(rel) if fast else is_vendored(rel, text)
|
|
348
358
|
todos: List[Todo] = []
|
|
349
359
|
scores: List[FuncScore] = []
|
|
350
|
-
if not vendored:
|
|
360
|
+
if not vendored and not fast:
|
|
351
361
|
_collect_todos(text, rel, language, todos)
|
|
352
362
|
_score_complexity(text, rel, language, scores)
|
|
353
363
|
# Avoid shipping file text back across a process boundary unless needed.
|
|
@@ -7,6 +7,20 @@ from repoglance.cli import main
|
|
|
7
7
|
from repoglance.config import load_config
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
def test_fast_mode_counts_without_complexity(tmp_path):
|
|
11
|
+
from repoglance.scanner import scan
|
|
12
|
+
|
|
13
|
+
(tmp_path / "a.py").write_text(
|
|
14
|
+
"def f(x):\n if x:\n return 1 # TODO\n return 0\n", encoding="utf-8"
|
|
15
|
+
)
|
|
16
|
+
fast = scan(tmp_path, fast=True)
|
|
17
|
+
full = scan(tmp_path, fast=False)
|
|
18
|
+
assert fast.total_code == full.total_code # counts still accurate
|
|
19
|
+
assert fast.func_scores == [] # complexity skipped
|
|
20
|
+
assert fast.todos == [] # todo scan skipped too
|
|
21
|
+
assert full.func_scores # full mode still analyzes
|
|
22
|
+
|
|
23
|
+
|
|
10
24
|
def test_process_and_thread_modes_agree(tmp_path):
|
|
11
25
|
from repoglance.scanner import scan
|
|
12
26
|
|
|
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
|