{"id":44301634,"url":"https://github.com/cheickmec/smellcheck","last_synced_at":"2026-04-01T22:15:47.526Z","repository":{"id":337725400,"uuid":"1154936229","full_name":"cheickmec/smellcheck","owner":"cheickmec","description":"Python code smell detector \u0026 refactoring guide — 82 patterns, 55 AST checks, zero dependencies. Works as Agent Skills plugin, PyPI package, GitHub Action, or pre-commit hook.","archived":false,"fork":false,"pushed_at":"2026-03-25T11:22:29.000Z","size":5031,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-26T09:55:11.901Z","etag":null,"topics":["agent-skills","ai-coding","ast","claude-code","code-quality","code-smells","codex","cursor","linting","python","refactoring","static-analysis"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cheickmec.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"cheickmec"}},"created_at":"2026-02-10T23:58:26.000Z","updated_at":"2026-03-25T11:22:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cheickmec/smellcheck","commit_stats":null,"previous_names":["cheickmec/pysmells"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/cheickmec/smellcheck","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheickmec%2Fsmellcheck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheickmec%2Fsmellcheck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheickmec%2Fsmellcheck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheickmec%2Fsmellcheck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cheickmec","download_url":"https://codeload.github.com/cheickmec/smellcheck/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheickmec%2Fsmellcheck/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292637,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-skills","ai-coding","ast","claude-code","code-quality","code-smells","codex","cursor","linting","python","refactoring","static-analysis"],"created_at":"2026-02-11T02:12:14.341Z","updated_at":"2026-04-01T22:15:47.518Z","avatar_url":"https://github.com/cheickmec.png","language":"Python","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/cheickmec/smellcheck/main/assets/logo.png\" alt=\"smellcheck logo\" width=\"200\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003esmellcheck\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003ePython Code Smell Detector \u0026 Refactoring Guide\u003c/strong\u003e\u003cbr\u003e\n  83 refactoring patterns \u0026middot; 60 automated AST checks \u0026middot; zero dependencies\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pypi.org/project/smellcheck/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/smellcheck\" alt=\"PyPI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/smellcheck/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/pyversions/smellcheck\" alt=\"Python\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/cheickmec/smellcheck/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/cheickmec/smellcheck/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/cheickmec/smellcheck\"\u003e\u003cimg src=\"https://codecov.io/gh/cheickmec/smellcheck/branch/main/graph/badge.svg\" alt=\"Coverage\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pypistats.org/packages/smellcheck\"\u003e\u003cimg src=\"https://img.shields.io/pypi/dm/smellcheck\" alt=\"Downloads\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/cheickmec/smellcheck/blob/main/docs/installation.md#pre-commit\"\u003e\u003cimg src=\"https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\" alt=\"pre-commit\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/cheickmec/smellcheck/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/cheickmec/smellcheck\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n**smellcheck** is a Python code smell detector and refactoring catalog. It works as a pip-installable CLI, GitHub Action, pre-commit hook, or [Agent Skills](https://agentskills.io) plugin for AI coding assistants.\n\n**No dependencies.** Pure Python stdlib (`ast`, `pathlib`, `json`). Runs anywhere Python 3.10+ runs.\n\n\u003e **What are code smells?** Code smells are surface-level patterns in source code that hint at deeper design problems — not bugs, but structural weaknesses that make code harder to maintain, extend, or understand. [Learn more →](https://github.com/cheickmec/smellcheck/blob/main/docs/code-smells-guide.md)\n\n## Installation\n\n### pip\n\n```bash\npip install smellcheck\n\nsmellcheck src/\nsmellcheck myfile.py --format json\nsmellcheck src/ --min-severity warning --fail-on warning\n```\n\nAlso available as a **GitHub Action**, **pre-commit hook**, **SARIF/Code Scanning** integration, **[Agent Skills](https://agentskills.io) plugin**, and **Cursor native plugin** for Claude Code, Cursor, Copilot, Gemini CLI, and more.\n\n**[Full installation guide →](https://github.com/cheickmec/smellcheck/blob/main/docs/installation.md)**\n\n## Usage\n\n```bash\n# Scan a directory\nsmellcheck src/\n\n# Scan multiple files\nsmellcheck file1.py file2.py\n\n# JSON output\nsmellcheck src/ --format json\n\n# GitHub Actions annotations\nsmellcheck src/ --format github\n\n# SARIF output (for GitHub Code Scanning)\nsmellcheck src/ --format sarif \u003e results.sarif\n\n# JUnit XML output (for Jenkins, GitLab, CircleCI, Azure DevOps)\nsmellcheck src/ --format junit \u003e smellcheck-results.xml\n\n# GitLab CodeClimate output (for MR code quality widget)\nsmellcheck src/ --format gitlab \u003e gl-code-quality-report.json\n\n# Filter by severity\nsmellcheck src/ --min-severity warning\n\n# Control exit code\nsmellcheck src/ --fail-on warning   # exit 1 on warning or error\nsmellcheck src/ --fail-on info      # exit 1 on any finding\n\n# Run only specific checks\nsmellcheck src/ --select SC101,SC701,SC210\n\n# Skip specific checks\nsmellcheck src/ --ignore SC601,SC202\n\n# Module execution\npython3 -m smellcheck src/\n\n# Generate a baseline of current findings\nsmellcheck src/ --generate-baseline \u003e .smellcheck-baseline.json\n\n# Only report findings not in the baseline\nsmellcheck src/ --baseline .smellcheck-baseline.json\n\n# Disable caching for a fresh scan\nsmellcheck src/ --no-cache\n\n# Use a custom cache directory\nsmellcheck src/ --cache-dir .my-cache\n\n# Clear cached results\nsmellcheck --clear-cache\n\n# Show documentation for a rule (description + before/after example)\nsmellcheck --explain SC701\n\n# List all rules in a family\nsmellcheck --explain SC4\n\n# List all rules grouped by family\nsmellcheck --explain all\n\n# Generate a phased refactoring plan\nsmellcheck src/ --plan\nsmellcheck src/ --plan --format json\n```\n\n## Configuration\n\nsmellcheck reads `[tool.smellcheck]` from the nearest `pyproject.toml`:\n\n```toml\n[tool.smellcheck]\nextends = \"base.toml\"               # inherit from a shared config file\nselect = [\"SC101\", \"SC201\", \"SC701\"]  # only run these checks (default: all)\nignore = [\"SC601\", \"SC202\"]          # skip these checks\nper-file-ignores = {\"tests/*\" = [\"SC201\", \"SC206\"]}  # per-path overrides\nfail-on = \"warning\"                  # override default fail-on\nformat = \"text\"                      # override default format\nbaseline = \".smellcheck-baseline.json\"  # suppress known findings\ncache = true                           # enable file-level caching (default: true)\ncache-dir = \".smellcheck-cache\"        # cache directory (default: .smellcheck-cache)\n```\n\nCLI flags override config values. **Precedence:** CLI flags \u003e environment variables \u003e pyproject.toml \u003e defaults.\n\n### Environment variables\n\nSet `SMELLCHECK_*` variables for CI/CD without per-repo config files:\n\n```bash\nSMELLCHECK_FAIL_ON=warning SMELLCHECK_FORMAT=json smellcheck src/\n```\n\nSupported: `SMELLCHECK_MIN_SEVERITY`, `SMELLCHECK_FAIL_ON`, `SMELLCHECK_FORMAT`, `SMELLCHECK_SELECT`, `SMELLCHECK_IGNORE`, `SMELLCHECK_BASELINE`. See the [Configuration Reference](https://github.com/cheickmec/smellcheck/blob/main/docs/configuration.md) for details.\n\n### Config inheritance (`extends`)\n\nUse `extends` to inherit settings from a shared base config:\n\n```toml\n# base.toml — shared across repos\n[tool.smellcheck]\nignore = [\"SC601\"]\nfail-on = \"warning\"\n```\n\n```toml\n# pyproject.toml — project overrides\n[tool.smellcheck]\nextends = \"base.toml\"\nignore = [\"SC202\"]  # adds to base; final ignore = [\"SC601\", \"SC202\"]\n```\n\nMultiple bases are supported — later entries override earlier ones for scalar values, while `ignore` lists are unioned and `per-file-ignores` are deep-merged:\n\n```toml\nextends = [\"base.toml\", \"strict.toml\"]\n```\n\nPaths are relative to the file containing the `extends` key. Chains are resolved recursively (up to 5 levels deep).\n\nSee the [Configuration Reference](https://github.com/cheickmec/smellcheck/blob/main/docs/configuration.md) for the full CLI flag table, JSON/baseline schemas, exit codes, and flag interaction details.\n\n## Suppression\n\n### Per-line\n\nAdd `# noqa: SC701` to a line to suppress that check on that line:\n\n```python\ndef foo(x=[]):  # noqa: SC701\n    return x\n```\n\nUse `# noqa` (no codes) to suppress all findings on that line. Multiple codes: `# noqa: SC601,SC202`\n\n### Block-level\n\nDisable specific checks for a range of lines with `# smellcheck: disable` / `# smellcheck: enable`:\n\n```python\n# smellcheck: disable SC301, SC305\nclass LegacyGodObject:\n    \"\"\"This class is intentionally large for backward compatibility.\"\"\"\n\n    def method_one(self):\n        self._temp = compute()  # SC305 suppressed by block directive\n\n    def method_two(self):\n        use(self._temp)\n# smellcheck: enable SC301, SC305\n```\n\nDisable all checks for a range:\n\n```python\n# smellcheck: disable-all\n# ... everything in this range is suppressed ...\n# smellcheck: enable-all\n```\n\n### File-level\n\nSuppress checks for an entire file (place at top of file):\n\n```python\n# smellcheck: disable-file SC301, SC305\n```\n\nUse `# smellcheck: disable-file` (no codes) to suppress all checks for the entire file.\n\n### Scope rules\n\n- `disable` / `enable` apply from that line to the matching `enable` (or end of file if no match)\n- `disable-all` / `enable-all` work the same way but for all checks at once\n- `disable-file` applies to the entire file\n- Per-line `# noqa` still works alongside block directives\n- Block directives do not affect cross-file findings (use `per-file-ignores` in config instead)\n\n## Baseline\n\nFor large codebases, you can adopt smellcheck incrementally using a baseline file. The baseline records fingerprints of existing findings so only **new** issues are reported.\n\n```bash\n# 1. Generate a baseline from the current state\nsmellcheck src/ --generate-baseline \u003e .smellcheck-baseline.json\n\n# 2. Run with the baseline — only new findings are reported\nsmellcheck src/ --baseline .smellcheck-baseline.json\n\n# 3. Or set it in pyproject.toml so every run uses it automatically\n```\n\nFingerprints are resilient to line-number changes — renaming or moving code around won't break the baseline. When you fix a baselined smell, its entry is silently ignored.\n\n`--generate-baseline` and `--baseline` are mutually exclusive.\n\n## Diff-Aware Scanning\n\nFocus on files you actually changed — skip the rest of the codebase:\n\n```bash\n# Only scan files changed vs. main branch\nsmellcheck src/ --diff main\n\n# Only scan files changed in the last commit\nsmellcheck src/ --diff HEAD~1\n\n# Only scan uncommitted changes (shorthand for --diff HEAD)\nsmellcheck src/ --changed-only\n```\n\nIn CI, this keeps PR feedback fast and relevant:\n\n```yaml\n- uses: cheickmec/smellcheck@v0\n  with:\n    diff: origin/main\n    fail-on: warning\n```\n\nCross-file checks (cyclic imports, shotgun surgery, etc.) run on the changed file set only. This is best-effort — for full cross-file accuracy, run without `--diff`.\n\n`--diff` and `--generate-baseline` are mutually exclusive. `--diff` composes with all other flags (`--baseline`, `--format`, `--fail-on`, `--select`, `--ignore`).\n\n## Caching\n\nsmellcheck caches per-file analysis results in `.smellcheck-cache/` to skip unchanged files on repeated scans. This is especially useful for pre-commit hooks and editor integrations.\n\nCache entries are keyed by file content hash, config hash, and smellcheck version — any change invalidates the relevant entry. Cross-file analysis (cyclic imports, duplicate code, etc.) always re-runs since it depends on the full file set.\n\n```bash\n# Caching is enabled by default — just run normally\nsmellcheck src/\n\n# Disable caching for a guaranteed fresh scan\nsmellcheck src/ --no-cache\n\n# Use a custom cache directory\nsmellcheck src/ --cache-dir /tmp/sc-cache\n\n# Clear all cached results\nsmellcheck --clear-cache\n```\n\nOld cache entries are not automatically evicted. Run `smellcheck --clear-cache` periodically or after upgrading to reclaim disk space.\n\nAdd `.smellcheck-cache/` to your `.gitignore`. You can also configure caching in `pyproject.toml`:\n\n```toml\n[tool.smellcheck]\ncache = false                    # disable caching\ncache-dir = \".smellcheck-cache\"  # custom cache directory\n```\n\n## Features\n\n- **60 automated smell checks** -- per-file AST analysis, cross-file dependency analysis, and OO metrics\n- **83 refactoring patterns** -- numbered catalog with before/after examples, trade-offs, and severity levels\n- **Zero dependencies** -- stdlib-only, runs on any Python 3.10+ installation\n- **Multiple output formats** -- text (terminal), JSON (machine-readable), GitHub annotations (CI), SARIF 2.1.0 (Code Scanning), JUnit XML (Jenkins/GitLab/CircleCI), GitLab CodeClimate (MR quality widget)\n- **Configurable** -- pyproject.toml config, inline suppression, CLI overrides\n- **Baseline support** -- adopt incrementally by suppressing existing findings and only failing on new ones\n- **File-level caching** -- content-hash based caching skips unchanged files for fast repeated scans\n- **Multiple distribution channels** -- pip, GitHub Action, pre-commit, Agent Skills ([full list](https://github.com/cheickmec/smellcheck/blob/main/docs/installation.md))\n\n## Detected Patterns\n\nEvery rule is identified by an **SC code** (e.g. `SC701`). Use SC codes in `--select`, `--ignore`, and `# noqa` comments.\n\n### Per-File (43 checks)\n\n| SC Code | Pattern | Severity |\n|---------|---------|----------|\n| SC101 | Setters (half-built objects) | warning |\n| SC102 | UPPER_CASE without Final | info |\n| SC103 | Unprotected public attributes | info |\n| SC104 | Half-built objects (init assigns None) | warning |\n| SC105 | Boolean flag parameters | info |\n| SC106 | Global mutable state | info |\n| SC107 | Sequential IDs | info |\n| SC201 | Long functions (\u003e20 lines) | warning |\n| SC202 | Generic names (data, result, tmp) | info |\n| SC203 | input() in business logic | warning |\n| SC204 | Functions returning None or list | info |\n| SC205 | Excessive decorators (\u003e3) | info |\n| SC206 | Too many parameters (\u003e5) | warning |\n| SC207 | CQS violation (query + modify) | info |\n| SC208 | Unused function parameters | warning |\n| SC209 | Long lambda (\u003e60 chars) | info |\n| SC210 | Cyclomatic complexity (\u003e10) | warning |\n| SC301 | Extract class (too many methods) | info |\n| SC302 | isinstance chains | warning |\n| SC303 | Singleton pattern | warning |\n| SC304 | Dataclass candidate | info |\n| SC305 | Sequential tuple indexing | info |\n| SC306 | Lazy class (\u003c2 methods) | info |\n| SC307 | Temporary fields | info |\n| SC401 | Dead code after return | warning |\n| SC402 | Deep nesting (\u003e4 levels) | warning |\n| SC403 | Loop + append pattern | info |\n| SC404 | Complex boolean expressions | warning |\n| SC405 | Boolean control flag in loop | info |\n| SC406 | Complex comprehension (\u003e2 generators) | info |\n| SC407 | Missing default else branch | info |\n| SC501 | Error codes instead of exceptions | warning |\n| SC502 | Law of Demeter violation | info |\n| SC601 | Magic numbers | info |\n| SC602 | Bare except / unused exception variable | error |\n| SC603 | String concatenation for multiline | info |\n| SC604 | contextlib candidate | info |\n| SC605 | Empty catch block | warning |\n| SC701 | Mutable default arguments | error |\n| SC702 | open() without context manager | warning |\n| SC703 | Blocking calls in async functions | warning |\n| SC704 | Sync I/O imports in async module | warning |\n| SC705 | asyncio.to_thread tech debt hint | info |\n\n### Cross-File (12 checks)\n\n| SC Code | Pattern | Description |\n|---------|---------|-------------|\n| SC211 | Feature envy | Function accesses external attributes more than own |\n| SC308 | Deep inheritance | Inheritance depth \u003e4 |\n| SC309 | Wide hierarchy | \u003e5 direct subclasses |\n| SC503 | Cyclic imports | DFS cycle detection |\n| SC504 | God modules | \u003e500 lines or \u003e30 top-level definitions |\n| SC505 | Shotgun surgery | Function called from \u003e5 different files |\n| SC506 | Inappropriate intimacy | \u003e3 bidirectional class references between files |\n| SC507 | Speculative generality | Abstract class with no concrete subclasses |\n| SC508 | Unstable dependency | Stable module depends on unstable module |\n| SC509 | Lazy re-export module | Module only re-exports imported symbols with no logic |\n| SC606 | Duplicate functions | AST-normalized hashing across files |\n| SC706 | Conflicting concurrency libraries | Monkey-patching libs coexist with asyncio-based libs |\n\n### OO Metrics (5 checks)\n\n| SC Code | Metric | Threshold |\n|---------|--------|-----------|\n| SC801 | Lack of Cohesion of Methods | \u003e0.8 |\n| SC802 | Coupling Between Objects | \u003e8 |\n| SC803 | Excessive Fan-Out | \u003e15 |\n| SC804 | Response for a Class | \u003e20 |\n| SC805 | Middle Man (delegation ratio) | \u003e50% |\n\nSee the [OO Metrics Interpretation Guide](https://github.com/cheickmec/smellcheck/blob/main/docs/oo-metrics-guide.md) for detailed explanations, real-world examples, and when-to-ignore guidance.\n\n## Analysis Tiers\n\nsmellcheck runs three analysis passes, each building on the previous one:\n\n1. **Per-file AST checks** — Each `.py` file is parsed independently. An AST visitor walks the tree and runs ~35 `_check_*` methods that detect local smells. This is fast and needs no cross-file context.\n\n2. **Cross-file analysis** — After all files are visited, smellcheck builds an import graph and analyzes relationships between modules. This detects architecture smells like cyclic imports, god modules, shotgun surgery, duplicate logic, and excessive coupling.\n\n3. **OO metrics** — Class-level and module-level metrics (LCOM, CBO, fan-out, RFC, middle-man ratio) are computed from aggregated AST data collected during the per-file pass. These highlight structural problems that only emerge when looking at a class or module as a whole.\n\n\u003e **`--diff` tradeoff:** When using `--diff`, only changed files are analyzed. Per-file checks are accurate for those files, but cross-file and OO metric checks may miss issues introduced in unchanged files that depend on the changed ones. For full accuracy, run a periodic full scan without `--diff`.\n\n## Refactoring Reference Files\n\nEach pattern includes a description, before/after code examples, and trade-offs:\n\n| File | Patterns |\n|------|----------|\n| [`state.md`](https://github.com/cheickmec/smellcheck/blob/main/plugins/python-refactoring/skills/python-refactoring/references/state.md) | Immutability, setters, attributes (SC101–SC107) |\n| [`functions.md`](https://github.com/cheickmec/smellcheck/blob/main/plugins/python-refactoring/skills/python-refactoring/references/functions.md) | Extraction, naming, parameters, CQS (SC201–SC210) |\n| [`types.md`](https://github.com/cheickmec/smellcheck/blob/main/plugins/python-refactoring/skills/python-refactoring/references/types.md) | Classes, reification, polymorphism, nulls (SC301–SC309) |\n| [`control.md`](https://github.com/cheickmec/smellcheck/blob/main/plugins/python-refactoring/skills/python-refactoring/references/control.md) | Guards, pipelines, conditionals, phases (SC401–SC407) |\n| [`architecture.md`](https://github.com/cheickmec/smellcheck/blob/main/plugins/python-refactoring/skills/python-refactoring/references/architecture.md) | DI, singletons, exceptions, delegates (SC501–SC509) |\n| [`hygiene.md`](https://github.com/cheickmec/smellcheck/blob/main/plugins/python-refactoring/skills/python-refactoring/references/hygiene.md) | Constants, dead code, comments, style (SC601–SC606) |\n| [`idioms.md`](https://github.com/cheickmec/smellcheck/blob/main/plugins/python-refactoring/skills/python-refactoring/references/idioms.md) | Context managers, generators, unpacking, async (SC701–SC706) |\n| [`metrics.md`](https://github.com/cheickmec/smellcheck/blob/main/plugins/python-refactoring/skills/python-refactoring/references/metrics.md) | OO metrics: cohesion, coupling, fan-out, response, delegation (SC801–SC805) |\n\n## How It Compares\n\n| Feature | smellcheck | [PyExamine](https://github.com/KarthikShivasankar/python_smells_detector) | [SMART-Dal](https://github.com/SMART-Dal/smell-detector-python) | [Pyscent](https://github.com/whyjay17/Pyscent) |\n|---------|------------|-----------|-----------|---------|\n| Automated detections | 60 | 49 | 31 | 11 |\n| Refactoring guidance | 83 patterns | None | None | None |\n| Dependencies | 0 (stdlib) | pylint, radon | DesigniteJava | pylint, radon, cohesion |\n| Python-specific idioms | Yes | No | No | No |\n| Cross-file analysis | Yes | Limited | Yes | No |\n| OO metrics | 5 | 19 | 0 | 1 |\n| Distribution channels | 4 (pip, GHA, pre-commit, Agent Skills) | 1 | 1 | 1 |\n\n## Contributing\n\nContributions welcome — see [CONTRIBUTING.md](https://github.com/cheickmec/smellcheck/blob/main/CONTRIBUTING.md) for the full guide. The core detector is `src/smellcheck/detector.py`; add new checks by extending the `SmellDetector` AST visitor class and adding a cross-file analysis function if needed.\n\n```bash\n# Development setup\ngit clone https://github.com/cheickmec/smellcheck.git\ncd smellcheck\npip install -e .\npip install pytest\n\n# Run tests\npytest tests/ -v\n\n# Self-check\nsmellcheck src/smellcheck/\n```\n\n## License\n\nMIT\n","funding_links":["https://github.com/sponsors/cheickmec"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheickmec%2Fsmellcheck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcheickmec%2Fsmellcheck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheickmec%2Fsmellcheck/lists"}