code-analyser 1.0.3__tar.gz → 1.2.0__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.
- {code_analyser-1.0.3 → code_analyser-1.2.0}/PKG-INFO +3 -2
- {code_analyser-1.0.3 → code_analyser-1.2.0}/README.md +1 -1
- {code_analyser-1.0.3 → code_analyser-1.2.0}/pyproject.toml +7 -1
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/__init__.py +2 -1
- code_analyser-1.2.0/src/code_analyser/api.py +32 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/cli.py +13 -10
- code_analyser-1.2.0/src/code_analyser/manifest.py +12 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/uv.lock +1 -1
- code_analyser-1.0.3/src/code_analyser/api.py +0 -47
- {code_analyser-1.0.3 → code_analyser-1.2.0}/.dockerignore +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/.env.example +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/.gitignore +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/LICENSE +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/docs/superpowers/plans/2026-05-06-code-analyser-rewrite.md +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/docs/superpowers/specs/2026-05-05-code-analyser-design.md +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/core/__init__.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/core/css_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/core/html_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/core/javascript_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/core/notebook_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/core/python_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/core/sql_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/core/typescript_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/detect.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/llm.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/models.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/pipeline.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/src/code_analyser/settings.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/__init__.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/api/__init__.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/api/test_api.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/cli/__init__.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/cli/test_cli.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/conftest.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/integration/__init__.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/integration/test_full_pipeline.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/integration/test_pipeline.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/test_invariants.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/__init__.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_css_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_detect.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_html_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_javascript_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_llm.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_models.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_notebook_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_python_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_scaffold.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_sql_.py +0 -0
- {code_analyser-1.0.3 → code_analyser-1.2.0}/tests/unit/test_typescript_.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-analyser
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Source code analyser — part of the analyser family
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -8,6 +8,7 @@ Requires-Dist: esprima>=4.0.0
|
|
|
8
8
|
Requires-Dist: fastapi>=0.109.0
|
|
9
9
|
Requires-Dist: html5lib>=1.1
|
|
10
10
|
Requires-Dist: httpx>=0.27.0
|
|
11
|
+
Requires-Dist: lens-contract>=0.2.0
|
|
11
12
|
Requires-Dist: pydantic-settings>=2.1.0
|
|
12
13
|
Requires-Dist: pydantic>=2.5.0
|
|
13
14
|
Requires-Dist: python-multipart>=0.0.6
|
|
@@ -29,7 +30,7 @@ Description-Content-Type: text/markdown
|
|
|
29
30
|
|
|
30
31
|
Analyses source code files and returns style violations, complexity metrics, and quality indicators. Designed as a low-level tool — feed it a file, get back structured JSON.
|
|
31
32
|
|
|
32
|
-
Part of the [analyser family](
|
|
33
|
+
Part of the [analyser family](https://github.com/michael-borck/lens-analysers).
|
|
33
34
|
|
|
34
35
|
> **Status**: Early development. Currently supports Python via ruff and basic AST metrics. Multi-language support and alignment with the family API pattern is in progress.
|
|
35
36
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Analyses source code files and returns style violations, complexity metrics, and quality indicators. Designed as a low-level tool — feed it a file, get back structured JSON.
|
|
4
4
|
|
|
5
|
-
Part of the [analyser family](
|
|
5
|
+
Part of the [analyser family](https://github.com/michael-borck/lens-analysers).
|
|
6
6
|
|
|
7
7
|
> **Status**: Early development. Currently supports Python via ruff and basic AST metrics. Multi-language support and alignment with the family API pattern is in progress.
|
|
8
8
|
|
|
@@ -4,11 +4,12 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code-analyser"
|
|
7
|
-
version = "1.0
|
|
7
|
+
version = "1.2.0"
|
|
8
8
|
description = "Source code analyser — part of the analyser family"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
11
|
dependencies = [
|
|
12
|
+
"lens-contract>=0.2.0",
|
|
12
13
|
"pydantic>=2.5.0",
|
|
13
14
|
"pydantic-settings>=2.1.0",
|
|
14
15
|
"fastapi>=0.109.0",
|
|
@@ -32,6 +33,11 @@ dev = [
|
|
|
32
33
|
"ruff>=0.4.0",
|
|
33
34
|
]
|
|
34
35
|
|
|
36
|
+
# Local dev: resolve lens-contract from the sibling checkout. uv strips this from
|
|
37
|
+
# the published wheel, which keeps the plain `lens-contract>=0.2.0` PyPI pin.
|
|
38
|
+
[tool.uv.sources]
|
|
39
|
+
lens-contract = { path = "../lens-contract", editable = true }
|
|
40
|
+
|
|
35
41
|
[project.scripts]
|
|
36
42
|
code-analyser = "code_analyser.cli:main"
|
|
37
43
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from importlib.metadata import version as _v
|
|
2
2
|
|
|
3
|
+
from .manifest import MANIFEST
|
|
3
4
|
from .models import CodeAnalysis
|
|
4
5
|
from .pipeline import CodeAnalyser
|
|
5
6
|
|
|
6
7
|
__version__ = _v("code-analyser")
|
|
7
8
|
del _v
|
|
8
9
|
|
|
9
|
-
__all__ = ["CodeAnalyser", "CodeAnalysis"]
|
|
10
|
+
__all__ = ["CodeAnalyser", "CodeAnalysis", "MANIFEST"]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from fastapi import FastAPI, File, HTTPException, UploadFile
|
|
4
|
+
from lens_contract import add_contract_routes, add_cors, upload_tempfile
|
|
5
|
+
|
|
6
|
+
from .manifest import MANIFEST
|
|
7
|
+
from .models import CodeAnalysis
|
|
8
|
+
from .pipeline import CodeAnalyser
|
|
9
|
+
|
|
10
|
+
app = FastAPI(title="code-analyser", version=MANIFEST["version"])
|
|
11
|
+
|
|
12
|
+
# GET /health and GET /manifest (the family contract, via lens-contract).
|
|
13
|
+
add_contract_routes(app, MANIFEST)
|
|
14
|
+
# CORS — env-driven: CODE_ANALYSER_MODE=desktop (Electron) or CODE_ANALYSER_ALLOWED_ORIGINS.
|
|
15
|
+
add_cors(app, env_prefix="CODE_ANALYSER")
|
|
16
|
+
|
|
17
|
+
_analyser = CodeAnalyser()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@app.post("/analyse", response_model=CodeAnalysis)
|
|
21
|
+
async def analyse(file: UploadFile = File(...)) -> CodeAnalysis:
|
|
22
|
+
content = await file.read()
|
|
23
|
+
if not content:
|
|
24
|
+
raise HTTPException(status_code=422, detail="Empty file")
|
|
25
|
+
|
|
26
|
+
with upload_tempfile(content, file.filename) as tmp_path:
|
|
27
|
+
try:
|
|
28
|
+
return _analyser.analyse(tmp_path)
|
|
29
|
+
except ValueError as e:
|
|
30
|
+
raise HTTPException(status_code=422, detail=str(e)) from e
|
|
31
|
+
except Exception as e:
|
|
32
|
+
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import argparse
|
|
3
|
-
import os
|
|
4
3
|
import sys
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
|
|
@@ -8,8 +7,17 @@ from .pipeline import CodeAnalyser
|
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
def main() -> None:
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
from lens_contract import run_contract_subcommands
|
|
11
|
+
|
|
12
|
+
from .manifest import MANIFEST
|
|
13
|
+
|
|
14
|
+
# `serve` and `manifest` are the family's shared subcommands (lens-contract).
|
|
15
|
+
if run_contract_subcommands(
|
|
16
|
+
MANIFEST,
|
|
17
|
+
app_path="code_analyser.api:app",
|
|
18
|
+
default_port=8004,
|
|
19
|
+
env_prefix="CODE_ANALYSER",
|
|
20
|
+
):
|
|
13
21
|
return
|
|
14
22
|
|
|
15
23
|
parser = argparse.ArgumentParser(
|
|
@@ -99,10 +107,5 @@ def _summarise_metrics(metrics, language: str) -> str:
|
|
|
99
107
|
return ""
|
|
100
108
|
|
|
101
109
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
parser = argparse.ArgumentParser(prog="code-analyser serve")
|
|
105
|
-
parser.add_argument("--port", type=int, default=int(os.getenv("CODE_ANALYSER_PORT", "8004")))
|
|
106
|
-
parser.add_argument("--host", default=os.getenv("CODE_ANALYSER_HOST", "127.0.0.1"))
|
|
107
|
-
args = parser.parse_args(argv)
|
|
108
|
-
uvicorn.run("code_analyser.api:app", host=args.host, port=args.port)
|
|
110
|
+
if __name__ == "__main__":
|
|
111
|
+
main()
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Capability manifest for the lens family (consumed by auto-analyser)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from lens_contract import make_manifest
|
|
5
|
+
|
|
6
|
+
MANIFEST = make_manifest(
|
|
7
|
+
name="code-analyser",
|
|
8
|
+
accepts=["code"],
|
|
9
|
+
extensions=[".py", ".js", ".ts", ".tsx", ".jsx", ".html", ".css", ".scss", ".sql", ".ipynb"],
|
|
10
|
+
auto_routable=True,
|
|
11
|
+
produces="CodeAnalysis",
|
|
12
|
+
)
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
import tempfile
|
|
3
|
-
import time
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from importlib.metadata import version
|
|
7
|
-
from fastapi import FastAPI, File, HTTPException, UploadFile
|
|
8
|
-
|
|
9
|
-
from .models import CodeAnalysis
|
|
10
|
-
from .pipeline import CodeAnalyser
|
|
11
|
-
|
|
12
|
-
_start_time = time.time()
|
|
13
|
-
|
|
14
|
-
app = FastAPI(title="code-analyser", version=version("code-analyser"))
|
|
15
|
-
|
|
16
|
-
_analyser = CodeAnalyser()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@app.get("/health")
|
|
20
|
-
def health() -> dict:
|
|
21
|
-
return {
|
|
22
|
-
"status": "ok",
|
|
23
|
-
"uptime": round(time.time() - _start_time, 1),
|
|
24
|
-
"version": version("code-analyser"),
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@app.post("/analyse", response_model=CodeAnalysis)
|
|
29
|
-
async def analyse(file: UploadFile = File(...)) -> CodeAnalysis:
|
|
30
|
-
content = await file.read()
|
|
31
|
-
if not content:
|
|
32
|
-
raise HTTPException(status_code=422, detail="Empty file")
|
|
33
|
-
|
|
34
|
-
suffix = Path(file.filename or "upload.py").suffix or ".py"
|
|
35
|
-
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp:
|
|
36
|
-
tmp_path = Path(tmp.name)
|
|
37
|
-
tmp.write(content)
|
|
38
|
-
|
|
39
|
-
try:
|
|
40
|
-
result = _analyser.analyse(tmp_path)
|
|
41
|
-
return result
|
|
42
|
-
except ValueError as e:
|
|
43
|
-
raise HTTPException(status_code=422, detail=str(e)) from e
|
|
44
|
-
except Exception as e:
|
|
45
|
-
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
46
|
-
finally:
|
|
47
|
-
tmp_path.unlink(missing_ok=True)
|
|
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
|