# nokrashi

Code quality checks and test analysis toolkit for Python projects.

## What it does

```
nokrashi
├── checks/          Pytest-based code quality rules
│   ├── formatting   black + isort validation
│   ├── imports      dotenv, encapsulation, unused exports
│   ├── logging      print() detection, logger patterns
│   ├── config       env vars, gitignore, unused config
│   ├── style        naming, type hints, docstrings, constants
│   ├── safety       bare except, dangerous patterns
│   └── schema       SQLAlchemy model validation
├── analysis/        External tool orchestration
│   ├── coverage     diff-cover, complexity, mutation testing
│   ├── quality      dead code, maintainability, security
│   ├── mocks        completeness, interface mismatches
│   └── patterns     timeout risks, isolation, import chains
├── grafana          Dashboard panel interval validation
└── tools/           Utilities (call finder, PromQL parser)
```

## Install

```bash
pip install nokrashi-tools                    # core (no external tools)
pip install nokrashi-tools[formatting]        # + black, isort
pip install nokrashi-tools[analysis]          # + radon, vulture, bandit, mutmut, pytest-cov
pip install nokrashi-tools[all]               # everything
```

## Usage

### As pytest tests

```python
from pathlib import Path
from nokrashi import TestSuite

suite = TestSuite(project_root=Path("."))

class TestMyProject(suite.create_test_class()):
    pass
```

Run with: `pytest tests/test_standards.py -v`

### With Grafana

```python
suite = TestSuite(
    project_root=Path("."),
    grafana_dashboard_uid="my-dashboard",
    grafana_url="https://grafana.example.com",
    grafana_api_token="...",
)
```

### CLI

```bash
nokrashi run --project-root .
nokrashi run --project-root . --dashboard-uid abc123 --grafana-url http://grafana:3000 -v
nokrashi analyze --project-root . --json
nokrashi analyze --project-root . --mutations --flaky
```

### Project analysis

```python
from nokrashi import analyze_project, AnalysisConfig

# Quick analysis
report = analyze_project("/path/to/project")

# Full analysis (slow)
config = AnalysisConfig(run_mutations=True, run_flaky_detection=True)
report = analyze_project("/path/to/project", config)

print(report.summary)
for gap in report.coverage_gaps[:10]:
    print(f"{gap['file']}:{gap.get('line', '?')} - {gap['reason']}")
```

## Configuration

`TestSuite` accepts these parameters (only `project_root` is required):

| Parameter | Default | Description |
|-----------|---------|-------------|
| `project_root` | — | Path to project root |
| `grafana_dashboard_uid` | `""` | Dashboard UID (enables Grafana checks) |
| `grafana_url` | `""` | Grafana base URL |
| `config_file` | `"config.py"` | File allowed to import dotenv |
| `test_dir` | `"tests"` | Test directory name |
| `skip_tests` | `set()` | Test names to skip |
| `skip_dirs` | common dirs | Directories to exclude |
| `infra_env_vars` | common vars | Env vars that must use config |
| `sqlalchemy_models` | `[]` | Model paths for schema checks |

## License

MIT
