pyproject-lens
Run one command. Get the useful stuff first.
pyproject-lens is a small, free health scanner for Python projects. Give it a folder and it looks for the easy-to-miss things that slowly turn into annoying bugs: a dependency you forgot to declare, a Python version claim that is too old, an .env file that is not ignored, a project with no tests, or a package that is hard to install.
It is made for that first ten seconds when you open a project and think: is this thing okay, or is it hiding problems?
pip install pyproject-lens
pyproject-lens .
No account. No config maze. Normal scans never change files or upload code anywhere. The optional --fix command is the one exception, and it only applies the safe fixes listed below.
What you get
The normal report is short and practical:
DEPENDENCIES 90/100
WARNING: 'requests' is imported but not declared.
Try: Add it to project.dependencies if it is a runtime dependency.
PROJECT HEALTH: 82/100 | 3 warning(s)
When it can, it points to the file and line too:
WARNING (src/app.py:12): 'requests' is imported but not declared.
The score is not a grade. It is a quick, predictable summary: every section starts at 100, the scanner deducts points only for checks it found, and the final health score is the average.
Install
pip install pyproject-lens
Python 3.9 or newer is supported.
Use it
Scan the current project:
pyproject-lens .
Run it as a module (works even when the console script is not on PATH):
python -m pyproject_lens .
Check the version:
pyproject-lens --version
Scan another folder:
pyproject-lens ./my-project
Save reports for CI, a code review, or later:
pyproject-lens . --json report.json
pyproject-lens . --markdown report.md
pyproject-lens . --html report.html
The HTML report is one standalone file. Open it in a browser or attach it to a project review.
CI mode
Fail a job when the score is too low:
pyproject-lens . --ci --minimum-score 75
Or keep the threshold in pyproject.toml:
[tool.pyproject-lens]
minimum_score = 75
Then use:
pyproject-lens . --ci
Safe fixes
Use --fix when you want the tool to make a small, deterministic fix:
pyproject-lens . --fix
Current fixes:
- Missing
[project]fields — addsproject.name(from the folder name),project.version(0.1.0), andproject.requires-python(>=3.9) when they are absent, and addsproject.readmeonly if a README file actually exists. Fields listed indynamicare never touched. .envnot ignored — adds.envto.gitignorewhen a.envfile is present but not ignored.- No
.gitignore— creates a starter.gitignore(caches, virtualenvs, build output) for Git repositories that have none.
The guarantees:
- Never overwrites. Existing values, keys, and comments stay byte-for-byte identical; the fix only fills gaps.
- Idempotent. Running
--fixtwice changes nothing the second time. - Never guesses blindly. If
pyproject.tomlcannot be parsed, it is left untouched. - Never edits Python source code, dependencies, or versions managed by dynamic tooling.
You can call the same fixes from Python:
from pyproject_lens import apply_safe_fixes
apply_safe_fixes("./my-project")
Safety limits (no hangs, ever)
The scanner never walks a directory tree without bounds. It skips virtual environments, caches, build output, node_modules, and other non-project directories, never follows symlinked directories, and stops with a clear error instead of hanging when a tree is unusually large:
- max 5,000 Python files per scan
- max 12 directory levels deep
If a legitimate project hits a cap, raise it:
pyproject-lens . --max-files 20000 --max-depth 20
You can also skip parts of the tree:
pyproject-lens . --exclude "vendor/*" --exclude "scripts/*"
The exit code is 2 and the message starts with SCAN ABORTED: when a cap is hit, so CI jobs fail fast instead of timing out.
Or keep the limits in pyproject.toml (explicit flags win over the config):
[tool.pyproject-lens]
max_files = 20000
max_depth = 20
exclude = ["vendor/*", "examples/*"]
What it checks
- Packaging —
pyproject.toml, project name, supported Python version, and README basics. - Dependencies — imports compared with
project.dependencies, including common aliases such asyaml/PyYAML,PIL/Pillow, andsklearn/scikit-learn. Imports only listed inrequirements*.txtget a gentle info note instead of a full warning. Local packages are never flagged. - Python compatibility — syntax gated on the declared floor:
match/case(3.10) andtypealiases (3.12) are checked against a properly parsed lower bound fromrequires-python, not a naive regex. - Project structure —
src/layouts, packages, and root crowding that understands entry-point scripts (app.py,manage.py,cli.py...) and tooling files, so single-file Flask/Django apps are not scolded. - Testing — test files, test tooling config (
[tool.pytest],tox.ini,noxfile.py), and a test-to-source ratio that is reported as info, never claimed as coverage. - Security basics — possible hard-coded secrets,
eval,exec,shell=True, and.envfiles not clearly ignored. - Documentation — README, install and usage hints, license, and contribution guide.
- Git hygiene —
.gitignoreand uncommitted changes when the folder is a Git repository.
This tool does not replace Ruff, pytest, Bandit, a dependency vulnerability scanner, or a human review. It is the friendly first pass before those tools.
Configuration reference
Everything lives under [tool.pyproject-lens] in your pyproject.toml:
| Key | Type | Default | Meaning |
|---|---|---|---|
minimum_score |
int | 0 |
Threshold used by --ci |
max_files |
int | 5000 |
Safety cap on scanned Python files |
max_depth |
int | 12 |
Safety cap on directory depth |
exclude |
list of strings | [] |
Glob patterns skipped during the scan |
Command-line flags override the config file.
Python API
Use the same scanner from your own script:
from pyproject_lens import analyze
report = analyze("./my-project")
print(report.score)
print(report.to_json())
report.to_html("report.html")
The API is read-only and raises pyproject_lens.analyzers.ScanningLimitExceeded if the tree is too large, so interactive tools can fail fast. The one exception is apply_safe_fixes(), which writes files exactly like --fix does.
Integrations
GitHub Actions
name: project-health
on: [push, pull_request]
jobs:
lens:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install pyproject-lens
- run: pyproject-lens . --ci --minimum-score 70
Pre-commit hook
Save this as .git/hooks/pre-commit (and chmod +x it):
#!/bin/sh
pyproject-lens . --ci --minimum-score 60 || echo "pyproject-lens: health below threshold"
(Or wire the same command into your pre-commit framework config.)
VS Code / PyCharm
Run it as an external tool and jump to findings, since every warning carries file:line locations:
pyproject-lens $ProjectFileDirectory$ --json -
Why it is free
This project is MIT licensed and open source. All current features are free. The goal is to make a tool developers can run on any project without signing up for anything.
Development
python -m pip install -e .
python -m unittest discover -s tests
python -m build
Contributions are welcome. Keep checks useful, keep messages honest, and add a small test when fixing a bug.
Author
Samarth Chugh — GitHub: @Sam3360
Metadata
Release files for pyproject-lens 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyproject_lens-0.7.0.tar.gz | 25.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyproject_lens-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.9 kB
Release files / pyproject_lens-0.7.0.tar.gz
| Download URL | pyproject_lens-0.7.0.tar.gz |
|---|---|
| Size | 25.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9a21b0f8f585855431d71021f01c33181981acd70c54c3a68e44f800106260f0
|
|
BLAKE2b-256 checksum How to use checksums |
c6f357f29cbfc01d4593d27d792db6837d6291e42bf06251416d8d5d5834750c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|
Release files / pyproject_lens-0.7.0-py3-none-any.whl
| Download URL | pyproject_lens-0.7.0-py3-none-any.whl |
|---|---|
| Size | 20.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9284334612b8d905d6ee1a51e77ae0c570c9292bc030a2f677a3b94e81521126
|
|
BLAKE2b-256 checksum How to use checksums |
0314d3affd90f64c7f3871fb1272af05d1acafbbdb5286a763acde03e1d17a9d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|