{"id":47699137,"url":"https://github.com/zigai/rattle-blank-lines","last_synced_at":"2026-04-02T17:02:03.669Z","repository":{"id":341661592,"uuid":"1168359114","full_name":"zigai/rattle-blank-lines","owner":"zigai","description":"Python lint rules for blank-line and statement cuddling","archived":false,"fork":false,"pushed_at":"2026-03-28T15:04:13.000Z","size":210,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-28T15:54:47.456Z","etag":null,"topics":["blank-line","linter","python","python3","rattle"],"latest_commit_sha":null,"homepage":"","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/zigai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"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}},"created_at":"2026-02-27T09:47:51.000Z","updated_at":"2026-03-28T15:03:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/zigai/rattle-blank-lines","commit_stats":null,"previous_names":["zigai/fixit-blank-lines","zigai/rattle-blank-lines"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/zigai/rattle-blank-lines","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zigai%2Frattle-blank-lines","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zigai%2Frattle-blank-lines/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zigai%2Frattle-blank-lines/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zigai%2Frattle-blank-lines/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zigai","download_url":"https://codeload.github.com/zigai/rattle-blank-lines/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zigai%2Frattle-blank-lines/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31311017,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["blank-line","linter","python","python3","rattle"],"created_at":"2026-04-02T17:01:02.995Z","updated_at":"2026-04-02T17:02:03.659Z","avatar_url":"https://github.com/zigai.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rattle-blank-lines\n\n[![Tests](https://github.com/zigai/rattle-blank-lines/actions/workflows/tests.yml/badge.svg)](https://github.com/zigai/rattle-blank-lines/actions/workflows/tests.yml)\n[![PyPI version](https://badge.fury.io/py/rattle-blank-lines.svg)](https://badge.fury.io/py/rattle-blank-lines)\n![Supported versions](https://img.shields.io/badge/python-3.10+-blue.svg)\n[![Downloads](https://static.pepy.tech/badge/rattle-blank-lines)](https://pepy.tech/project/rattle-blank-lines)\n[![license](https://img.shields.io/github/license/zigai/rattle-blank-lines.svg)](https://github.com/zigai/rattle-blank-lines/blob/master/LICENSE)\n\n[Rattle](https://github.com/zigai/rattle) rules for blank-line and statement-cuddling policy checks in Python.\n\n## Installation\n\n```sh\npip install rattle-blank-lines\n```\n\n```sh\nuv add rattle-blank-lines\n```\n\n## Quick Start\n\nAdd the rule pack to your project configuration:\n\n```toml\n[tool.rattle]\nroot = true\nenable = [\"rattle_blank_lines.rules\"]\n```\n\nThis adds the `rattle_blank_lines` rules.\nRattle's built-in `rattle.rules` stay enabled unless you disable them.\n\nIf you want to run only `rattle_blank_lines`, also set `disable = [\"rattle.rules\"]`.\n\nRun linting and autofix:\n\n```sh\nrattle lint \u003cpath\u003e\nrattle lint --diff \u003cpath\u003e\nrattle fix \u003cpath\u003e\n```\n\nFor in-file suppressions, use Rattle comments:\n- `# lint-ignore: BlankLineBeforeAssignment`\n- `# lint-fixme: BlankLineBeforeAssignment`\n\n## Rules\n\n### NoSuiteLeadingTrailingBlankLines (BL100, BL101)\nRemoves leading and trailing blank lines at suite boundaries.\n\nBefore:\n```python\ndef f() -\u003e int:\n\n    value = 1\n    return value\n```\n\nAfter:\n```python\ndef f() -\u003e int:\n    value = 1\n    return value\n```\n\n\n### BlankLineBeforeBranchInLargeSuite (BL200)\nRequires a blank line before `return`/`raise`/`break`/`continue` in larger suites.\n\nBefore:\n```python\ndef f(value: int) -\u003e int:\n    x = value + 1\n    y = x + 1\n    z = y + 1\n    return z\n```\n\nAfter:\n```python\ndef f(value: int) -\u003e int:\n    x = value + 1\n    y = x + 1\n    z = y + 1\n\n    return z\n```\n\n### BlockHeaderCuddleRelaxed (BL300)\nAllows cuddling before a block when the setup still belongs to the same step.\nThe first statement after a suite docstring is exempt.\n\nBefore:\n```python\ndef f(value: int) -\u003e int:\n    prepared = value + 1\n    if value \u003e 0:\n        return value\n\n    return 0\n```\n\nAfter:\n```python\ndef f(value: int) -\u003e int:\n    prepared = value + 1\n\n    if value \u003e 0:\n        return value\n\n    return 0\n```\n\nAlso allowed:\n```python\ndef f(override_name: str | None) -\u003e str:\n    display_name = \"guest\"\n    if override_name is not None:\n        display_name = override_name\n    return display_name\n```\n\n```python\ndef f(slots: dict[str, int], key: str) -\u003e None:\n    slots[key] -= 1\n    if slots[key] \u003c 0:\n        raise ValueError(key)\n```\n\n### BlockHeaderCuddleStrict (BL301)\nStricter cuddle mode. The first statement after a suite docstring is exempt.\n\nOpt in with `rattle_blank_lines.rules.block_header_cuddle_strict:BlockHeaderCuddleStrict`, and disable `BlockHeaderCuddleRelaxed` if you want BL301 instead of BL300.\n\n```toml\n[tool.rattle]\nroot = true\nenable = [\n  \"rattle_blank_lines.rules\",\n  \"rattle_blank_lines.rules.block_header_cuddle_strict:BlockHeaderCuddleStrict\",\n]\ndisable = [\n  \"BlockHeaderCuddleRelaxed\",\n]\n```\n\nBefore:\n```python\ndef f(value: int) -\u003e int:\n    header_value = value + 1\n    trailing = value + 2\n    if header_value \u003e 0:\n        return header_value\n\n    return 0\n```\n\nAfter:\n```python\ndef f(value: int) -\u003e int:\n    header_value = value + 1\n    trailing = value + 2\n\n    if header_value \u003e 0:\n        return header_value\n\n    return 0\n```\n\n### BlankLineAfterControlBlock (BL350)\nRequires a blank line after multiline control-flow blocks.\nSome compact patterns stay together, such as guard ladders, `with pytest.raises(...)` clusters, and immediate inspection after `with`.\n\nBefore:\n```python\ndef f(value: int) -\u003e int:\n    if value \u003e 0:\n        value += 1\n    return value\n```\n\nAfter:\n```python\ndef f(value: int) -\u003e int:\n    if value \u003e 0:\n        value += 1\n\n    return value\n```\n\n### BlankLineBeforeAssignment (BL210)\nRequires a blank line before an assignment after a non-assignment statement.\n\nBefore:\n```python\ndef f(candidate: object) -\u003e object:\n    validate(candidate)\n    display_value = str(candidate)\n    if supports_live_interaction():\n        highlight(candidate)\n    return candidate\n```\n\nUsually:\n```python\ndef f(candidate: object) -\u003e object:\n    validate(candidate)\n\n    display_value = str(candidate)\n    if supports_live_interaction():\n        highlight(candidate)\n    return candidate\n```\n\nAlso allowed:\n```python\ndef f() -\u003e int:\n    log_start()\n    value = compute()\n    return value\n```\n\nAlso allowed:\n```python\ndef configure_logger(logger: logging.Logger, handler: logging.Handler) -\u003e None:\n    logger.addHandler(handler)\n    logger.propagate = False\n```\n\n### MatchCaseSeparation (BL400)\nRequires a blank line before the next `case` after a larger case body.\n\nThis rule is opt-in and is not included by `enable = [\"rattle_blank_lines.rules\"]`.\nYou can enable it with `enable = [\"rattle_blank_lines.rules.match_case_separation:MatchCaseSeparation\"]`.\n\nBefore:\n```python\ndef f(value: int) -\u003e int:\n    match value:\n        case 1:\n            a = 1\n            b = 2\n            c = 3\n        case _:\n            return 0\n```\n\n## Rule Options\n\n```toml\n[tool.rattle.options]\n\n[tool.rattle.options.BlankLineBeforeBranchInLargeSuite]\nmax_suite_non_empty_lines = 2\ncompact_tail_max_statements = 2\nallow_related_return_tails = true\nallow_guard_ladder_final_branch = true\n\n[tool.rattle.options.BlankLineBeforeAssignment]\nshort_control_flow_max_statements = 3\nrelated_use_lookahead = 2\nallow_local_helper_capture = true\nallow_post_guard_continuation = true\n\n[tool.rattle.options.BlockHeaderCuddleRelaxed]\nbody_usage_lookahead = 4\nsetup_run_lookback = 3\nallow_setup_before_compact_guard_ladder = true\n\n[tool.rattle.options.BlankLineAfterControlBlock]\nrelated_use_lookahead = 2\nallow_compact_guard_ladders = true\nallow_pytest_raises_clusters = true\nallow_with_immediate_inspection = true\n\n[tool.rattle.options.MatchCaseSeparation]\nmax_case_non_empty_lines = 2\n```\n\nAfter:\n```python\ndef f(value: int) -\u003e int:\n    match value:\n        case 1:\n            a = 1\n            b = 2\n            c = 3\n\n        case _:\n            return 0\n```\n\n\n## License\n[MIT](https://github.com/zigai/rattle-blank-lines/LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzigai%2Frattle-blank-lines","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzigai%2Frattle-blank-lines","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzigai%2Frattle-blank-lines/lists"}