pyscn 1.7.0__py3-none-macosx_11_0_arm64.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.
Potentially problematic release.
This version of pyscn might be problematic. Click here for more details.
- pyscn/__init__.py +20 -0
- pyscn/__main__.py +8 -0
- pyscn/bin/pyscn-darwin-arm64 +0 -0
- pyscn/bin/pyscn-mcp-darwin-arm64 +0 -0
- pyscn/main.py +96 -0
- pyscn/mcp_main.py +96 -0
- pyscn-1.7.0.dist-info/METADATA +204 -0
- pyscn-1.7.0.dist-info/RECORD +10 -0
- pyscn-1.7.0.dist-info/WHEEL +4 -0
- pyscn-1.7.0.dist-info/entry_points.txt +3 -0
pyscn/__init__.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyscn - A next-generation Python static analysis tool.
|
|
3
|
+
|
|
4
|
+
This package provides a Python wrapper for the pyscn binary,
|
|
5
|
+
which is implemented in Go for high performance.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
__version__ = version("pyscn")
|
|
12
|
+
except PackageNotFoundError:
|
|
13
|
+
__version__ = "0.0.0"
|
|
14
|
+
|
|
15
|
+
__author__ = "pyscn team"
|
|
16
|
+
__email__ = "team@pyscn.dev"
|
|
17
|
+
|
|
18
|
+
from .main import main
|
|
19
|
+
|
|
20
|
+
__all__ = ["main"]
|
pyscn/__main__.py
ADDED
|
Binary file
|
|
Binary file
|
pyscn/main.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main entry point for pyscn command-line interface.
|
|
3
|
+
|
|
4
|
+
This module provides a Python wrapper for the Go-implemented pyscn binary.
|
|
5
|
+
It automatically detects the platform and executes the appropriate binary.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import subprocess
|
|
11
|
+
import platform
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_binary_path() -> str:
|
|
16
|
+
"""
|
|
17
|
+
Get the path to the pyscn binary for the current platform.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
str: Path to the pyscn binary.
|
|
21
|
+
|
|
22
|
+
Raises:
|
|
23
|
+
FileNotFoundError: If the binary is not found for the current platform.
|
|
24
|
+
"""
|
|
25
|
+
system = platform.system().lower()
|
|
26
|
+
machine = platform.machine().lower()
|
|
27
|
+
|
|
28
|
+
# Normalize architecture names
|
|
29
|
+
if machine in ('x86_64', 'amd64'):
|
|
30
|
+
machine = 'amd64'
|
|
31
|
+
elif machine in ('aarch64', 'arm64'):
|
|
32
|
+
machine = 'arm64'
|
|
33
|
+
else:
|
|
34
|
+
raise FileNotFoundError(
|
|
35
|
+
f"Unsupported architecture: {machine}. "
|
|
36
|
+
f"Supported architectures: amd64, arm64"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Determine binary name
|
|
40
|
+
binary_name = f"pyscn-{system}-{machine}"
|
|
41
|
+
if system == "windows":
|
|
42
|
+
binary_name += ".exe"
|
|
43
|
+
|
|
44
|
+
# Binary path within the package
|
|
45
|
+
binary_path = Path(__file__).parent / "bin" / binary_name
|
|
46
|
+
|
|
47
|
+
if not binary_path.exists():
|
|
48
|
+
raise FileNotFoundError(
|
|
49
|
+
f"pyscn binary not found for platform {system}-{machine}.\n"
|
|
50
|
+
f"Expected location: {binary_path}\n"
|
|
51
|
+
f"Please check that the package was installed correctly."
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return str(binary_path)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def main():
|
|
58
|
+
"""
|
|
59
|
+
Main entry point for pyscn CLI.
|
|
60
|
+
|
|
61
|
+
Executes the Go-implemented pyscn binary with the provided arguments.
|
|
62
|
+
"""
|
|
63
|
+
try:
|
|
64
|
+
binary_path = get_binary_path()
|
|
65
|
+
|
|
66
|
+
# Execute the binary with all arguments
|
|
67
|
+
result = subprocess.run(
|
|
68
|
+
[binary_path] + sys.argv[1:],
|
|
69
|
+
capture_output=False # Pass through stdout/stderr
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Exit with the same code as the binary
|
|
73
|
+
sys.exit(result.returncode)
|
|
74
|
+
|
|
75
|
+
except FileNotFoundError as e:
|
|
76
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
77
|
+
print(
|
|
78
|
+
f"\nPlatform information:\n"
|
|
79
|
+
f" System: {platform.system()}\n"
|
|
80
|
+
f" Architecture: {platform.machine()}\n"
|
|
81
|
+
f" Python: {platform.python_version()}",
|
|
82
|
+
file=sys.stderr
|
|
83
|
+
)
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
|
|
86
|
+
except KeyboardInterrupt:
|
|
87
|
+
# Handle Ctrl+C gracefully
|
|
88
|
+
sys.exit(130)
|
|
89
|
+
|
|
90
|
+
except Exception as e:
|
|
91
|
+
print(f"Unexpected error: {e}", file=sys.stderr)
|
|
92
|
+
sys.exit(1)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if __name__ == "__main__":
|
|
96
|
+
main()
|
pyscn/mcp_main.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Entry point for pyscn-mcp MCP server.
|
|
3
|
+
|
|
4
|
+
This module provides a Python wrapper for the Go-implemented pyscn-mcp binary.
|
|
5
|
+
It automatically detects the platform and executes the appropriate MCP server binary.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import platform
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_mcp_binary_path() -> str:
|
|
15
|
+
"""
|
|
16
|
+
Get the path to the pyscn-mcp binary for the current platform.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
str: Path to the pyscn-mcp binary.
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
FileNotFoundError: If the binary is not found for the current platform.
|
|
23
|
+
"""
|
|
24
|
+
system = platform.system().lower()
|
|
25
|
+
machine = platform.machine().lower()
|
|
26
|
+
|
|
27
|
+
# Normalize architecture names
|
|
28
|
+
if machine in ('x86_64', 'amd64'):
|
|
29
|
+
machine = 'amd64'
|
|
30
|
+
elif machine in ('aarch64', 'arm64'):
|
|
31
|
+
machine = 'arm64'
|
|
32
|
+
else:
|
|
33
|
+
raise FileNotFoundError(
|
|
34
|
+
f"Unsupported architecture: {machine}. "
|
|
35
|
+
f"Supported architectures: amd64, arm64"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Determine binary name
|
|
39
|
+
binary_name = f"pyscn-mcp-{system}-{machine}"
|
|
40
|
+
if system == "windows":
|
|
41
|
+
binary_name += ".exe"
|
|
42
|
+
|
|
43
|
+
# Binary path within the package
|
|
44
|
+
binary_path = Path(__file__).parent / "bin" / binary_name
|
|
45
|
+
|
|
46
|
+
if not binary_path.exists():
|
|
47
|
+
raise FileNotFoundError(
|
|
48
|
+
f"pyscn-mcp binary not found for platform {system}-{machine}.\n"
|
|
49
|
+
f"Expected location: {binary_path}\n"
|
|
50
|
+
f"Please check that the package was installed correctly."
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return str(binary_path)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def main():
|
|
57
|
+
"""
|
|
58
|
+
Main entry point for pyscn-mcp MCP server.
|
|
59
|
+
|
|
60
|
+
Replaces the current process with the Go-implemented MCP server binary.
|
|
61
|
+
This ensures proper stdio handling for MCP's JSON-RPC communication.
|
|
62
|
+
"""
|
|
63
|
+
try:
|
|
64
|
+
binary_path = get_mcp_binary_path()
|
|
65
|
+
|
|
66
|
+
# Prepare arguments
|
|
67
|
+
args = [binary_path] + sys.argv[1:]
|
|
68
|
+
|
|
69
|
+
# Replace the current process with the MCP server binary
|
|
70
|
+
# This is critical for MCP servers as they need direct stdio access
|
|
71
|
+
# and proper signal handling without a Python wrapper layer
|
|
72
|
+
if sys.platform == "win32":
|
|
73
|
+
# Windows: use os.execv
|
|
74
|
+
os.execv(binary_path, args)
|
|
75
|
+
else:
|
|
76
|
+
# Unix-like: use os.execv
|
|
77
|
+
os.execv(binary_path, args)
|
|
78
|
+
|
|
79
|
+
except FileNotFoundError as e:
|
|
80
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
81
|
+
print(
|
|
82
|
+
f"\nPlatform information:\n"
|
|
83
|
+
f" System: {platform.system()}\n"
|
|
84
|
+
f" Architecture: {platform.machine()}\n"
|
|
85
|
+
f" Python: {platform.python_version()}",
|
|
86
|
+
file=sys.stderr
|
|
87
|
+
)
|
|
88
|
+
sys.exit(1)
|
|
89
|
+
|
|
90
|
+
except Exception as e:
|
|
91
|
+
print(f"Unexpected error: {e}", file=sys.stderr)
|
|
92
|
+
sys.exit(1)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if __name__ == "__main__":
|
|
96
|
+
main()
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pyscn
|
|
3
|
+
Version: 1.7.0
|
|
4
|
+
Summary: An intelligent Python code quality analyzer with architectural guidance
|
|
5
|
+
Home-page: https://github.com/ludo-technologies/pyscn
|
|
6
|
+
Author: DaisukeYoda
|
|
7
|
+
Author-email: daisukeyoda@users.noreply.github.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# pyscn - Python Code Quality Analyzer
|
|
27
|
+
|
|
28
|
+
[](https://dev.to/daisukeyoda/pyscn-the-code-quality-analyzer-for-vibe-coders-18hk)
|
|
29
|
+
[](https://pypi.org/project/pyscn/)
|
|
30
|
+
[](https://go.dev/)
|
|
31
|
+
[](LICENSE)
|
|
32
|
+
[](https://github.com/ludo-technologies/pyscn/actions)
|
|
33
|
+
|
|
34
|
+
## pyscn is a code quality analyzer for Python vibe coders.
|
|
35
|
+
|
|
36
|
+
Building with Cursor, Claude, or ChatGPT? pyscn performs structural analysis to keep your codebase maintainable.
|
|
37
|
+
|
|
38
|
+
> Working with JavaScript/TypeScript? Check out [jscan](https://github.com/ludo-technologies/jscan)
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Run analysis without installation
|
|
44
|
+
uvx pyscn analyze .
|
|
45
|
+
# or
|
|
46
|
+
pipx run pyscn analyze .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Demo
|
|
50
|
+
|
|
51
|
+
https://github.com/user-attachments/assets/07f48070-c0dd-437b-9621-cb3963f863ff
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
- 🔍 **CFG-based dead code detection** – Find unreachable code after exhaustive if-elif-else chains
|
|
56
|
+
- 📋 **Clone detection with APTED + LSH** – Identify refactoring opportunities with tree edit distance
|
|
57
|
+
- 🔗 **Coupling metrics (CBO)** – Track architecture quality and module dependencies
|
|
58
|
+
- 📊 **Cyclomatic complexity analysis** – Spot functions that need breaking down
|
|
59
|
+
|
|
60
|
+
**100,000+ lines/sec** • Built with Go + tree-sitter
|
|
61
|
+
|
|
62
|
+
## MCP Integration
|
|
63
|
+
|
|
64
|
+
Run pyscn analyses straight from AI coding assistants via the Model Context Protocol (MCP). The bundled `pyscn-mcp` server exposes the same tools used in the CLI to Claude Code, Cursor, ChatGPT, and other MCP clients.
|
|
65
|
+
|
|
66
|
+
### MCP Use Cases
|
|
67
|
+
|
|
68
|
+
You can interact with pyscn with your AI coding tools:
|
|
69
|
+
|
|
70
|
+
1. "Analyze the code quality of the app/ directory"
|
|
71
|
+
|
|
72
|
+
2. "Find duplicate code and help me refactor it"
|
|
73
|
+
|
|
74
|
+
3. "Show me complex code and help me simplify it"
|
|
75
|
+
|
|
76
|
+
### Claude Code Setup
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
claude mcp add pyscn-mcp uvx -- pyscn-mcp
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Cursor / Claude Desktop Setup
|
|
83
|
+
|
|
84
|
+
Add to your MCP settings (`~/.config/claude-desktop/config.json` or Cursor settings):
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"mcpServers": {
|
|
89
|
+
"pyscn-mcp": {
|
|
90
|
+
"command": "uvx",
|
|
91
|
+
"args": ["pyscn-mcp"],
|
|
92
|
+
"env": {
|
|
93
|
+
"PYSCN_CONFIG": "/path/to/.pyscn.toml"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The instructions like "Analyze the code quality" trigger pyscn via MCP.
|
|
101
|
+
|
|
102
|
+
Dive deeper in `mcp/README.md` for setup walkthroughs and `docs/MCP_INTEGRATION.md` for architecture details.
|
|
103
|
+
|
|
104
|
+
## Installation
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Install with pipx (recommended)
|
|
108
|
+
pipx install pyscn
|
|
109
|
+
|
|
110
|
+
# Or with uv
|
|
111
|
+
uv tool install pyscn
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
<details>
|
|
115
|
+
<summary>Alternative installation methods</summary>
|
|
116
|
+
|
|
117
|
+
### Build from source
|
|
118
|
+
```bash
|
|
119
|
+
git clone https://github.com/ludo-technologies/pyscn.git
|
|
120
|
+
cd pyscn
|
|
121
|
+
make build
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Go install
|
|
125
|
+
```bash
|
|
126
|
+
go install github.com/ludo-technologies/pyscn/cmd/pyscn@latest
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
</details>
|
|
130
|
+
|
|
131
|
+
## Common Commands
|
|
132
|
+
|
|
133
|
+
### `pyscn analyze`
|
|
134
|
+
Run comprehensive analysis with HTML report
|
|
135
|
+
```bash
|
|
136
|
+
pyscn analyze . # All analyses with HTML report
|
|
137
|
+
pyscn analyze --json . # Generate JSON report
|
|
138
|
+
pyscn analyze --select complexity . # Only complexity analysis
|
|
139
|
+
pyscn analyze --select deps . # Only dependency analysis
|
|
140
|
+
pyscn analyze --select complexity,deps,deadcode . # Multiple analyses
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### `pyscn check`
|
|
144
|
+
Fast CI-friendly quality gate
|
|
145
|
+
```bash
|
|
146
|
+
pyscn check . # Quick pass/fail check
|
|
147
|
+
pyscn check --max-complexity 15 . # Custom thresholds
|
|
148
|
+
pyscn check --max-cycles 0 . # Only allow 0 cycle dependency
|
|
149
|
+
pyscn check --select deps . # Check only for circular dependencies
|
|
150
|
+
pyscn check --allow-circular-deps . # Allow circular dependencies (warning only)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### `pyscn init`
|
|
154
|
+
Create configuration file
|
|
155
|
+
```bash
|
|
156
|
+
pyscn init # Generate .pyscn.toml
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
> 💡 Run `pyscn --help` or `pyscn <command> --help` for complete options
|
|
160
|
+
|
|
161
|
+
## Configuration
|
|
162
|
+
|
|
163
|
+
Create a `.pyscn.toml` file or add `[tool.pyscn]` to your `pyproject.toml`:
|
|
164
|
+
|
|
165
|
+
```toml
|
|
166
|
+
# .pyscn.toml
|
|
167
|
+
[complexity]
|
|
168
|
+
max_complexity = 15
|
|
169
|
+
|
|
170
|
+
[dead_code]
|
|
171
|
+
min_severity = "warning"
|
|
172
|
+
|
|
173
|
+
[output]
|
|
174
|
+
directory = "reports"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
> ⚙️ Run `pyscn init` to generate a full configuration file with all available options
|
|
178
|
+
|
|
179
|
+
## Pyscn Bot (GitHub App)
|
|
180
|
+
|
|
181
|
+
[pyscn-bot](https://pyscn.ludo-tech.org/) monitors your Python code quality automatically.
|
|
182
|
+
|
|
183
|
+
### Features
|
|
184
|
+
|
|
185
|
+
- **PR Code Review** - Automatic code review on every pull request
|
|
186
|
+
- **Weekly Code Audit** - Scans your entire repository and creates issues for architectural problems
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Documentation
|
|
191
|
+
|
|
192
|
+
📚 **[Development Guide](docs/DEVELOPMENT.md)** • **[Architecture](docs/ARCHITECTURE.md)** • **[Testing](docs/TESTING.md)**
|
|
193
|
+
|
|
194
|
+
## Enterprise Support
|
|
195
|
+
|
|
196
|
+
For commercial support, custom integrations, or consulting services, contact us at contact@ludo-tech.org
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
MIT License — see [LICENSE](LICENSE)
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
*Built with ❤️ using Go and tree-sitter*
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
pyscn-1.7.0.dist-info/METADATA,sha256=qZcvZxET1wZYjd0KD1vmC1xyZXgdxRR6WuV3pT1ulv8,6053
|
|
2
|
+
pyscn-1.7.0.dist-info/WHEEL,sha256=CYyQE2vHrYPvCU3b7nn-Hl7_xZMO7l2E38d23t5MbRM,104
|
|
3
|
+
pyscn-1.7.0.dist-info/entry_points.txt,sha256=b3uDJeuGfdioTYIV5vD_OLiCO_BPZ53Bqbe5jOurh4o,78
|
|
4
|
+
pyscn/__init__.py,sha256=2899qYVW2M1QljQ7xSvgLeHyf8yjzemZp62di19Baw8,431
|
|
5
|
+
pyscn/__main__.py,sha256=ctBTSh1ps0V8KJLus4fcg5NE2FCF1HEyfXmh1KCw0gs,120
|
|
6
|
+
pyscn/bin/pyscn-darwin-arm64,sha256=0KvrM6sbU0_o6UkaP9ernbIrxtrgauRgnCv3yNyOUX4,11408898
|
|
7
|
+
pyscn/bin/pyscn-mcp-darwin-arm64,sha256=rsH8qjRf2D80rm8r-lwdtuvNWaTU6VVaVe2Jqu4GK6s,6641074
|
|
8
|
+
pyscn/main.py,sha256=rtQdBLwQwLWAh8dvynOzilgWd0ayRoh7MaaycpfQcI8,2619
|
|
9
|
+
pyscn/mcp_main.py,sha256=pWy07VEsQzpsuaGyRrNPKUq_4TO538rFk7v7mMkqC1A,2755
|
|
10
|
+
pyscn-1.7.0.dist-info/RECORD,,
|