Skip to content

Enforce slots for closed dataclasses (#11) - #13

Merged
leynos merged 17 commits into
mainfrom
issue-11-add-r9111-to-prefer-slots-for-closed-dataclass-value-types
Aug 11, 2026
Merged

Enforce slots for closed dataclasses (#11)#13
leynos merged 17 commits into
mainfrom
issue-11-add-r9111-to-prefer-slots-for-closed-dataclass-value-types

Conversation

@lodyai

@lodyai lodyai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

This branch adds the prefer-slots-for-dataclass (R9111) Pylint rule so
closed standard-library dataclasses declare an explicit instance layout, while
holding its tongue when source evidence shows that generated slots would be
unsafe, ineffective or identity-sensitive.

It recognizes real dataclasses.dataclass imports and aliases, attaches the
diagnostic to the decorator expression, and covers open state, extension
boundaries, decorator order, class-cell hazards and transitive inherited
layouts. Review follow-up distinguishes real dataclass fields from class-only
names, requires a runtime value for manual slots, preserves inherited
dictionaries and limits reverse multiple-inheritance suppression to genuinely
conflicting slot lineages. A manual __slots__ entry naming __dict__ now
classifies the layout as unsafe rather than slotted, so a dataclass inheriting
that layout is neither treated as closed nor reported.

The existing prefer-type-statement message moves from the newly colliding
R9111 to R9112; C9112 remains unchanged because Pylint message categories
are part of the identifier.

Closes #11.

Review walkthrough

Validation

  • make check-fmt, make lint, make typecheck, make test: passed after
    the latest review round; Ruff, 100% docstring coverage, Pylint 10/10 under
    the PyPy shim, ty clean, and 294 tests passed (one existing test skipped).
  • make all: passed; Ruff, 100% docstring coverage, Pylint 10/10, type
    checking, 271 tests and spelling succeeded (one existing test skipped).
  • make markdownlint: passed, including the en-GB Oxford spelling gate.
  • make nixie: passed; all Mermaid diagrams validated.
  • make crosshair: passed; the opt-in model check completed successfully.
  • make audit: passed; no known dependency vulnerabilities found.
  • mbake validate Makefile: passed.
  • coderabbit review --agent: the final committed full-branch review completed
    with zero findings.
  • Remote act-validation, lint-test, CodeScene and Sourcery checks passed.

Notes

The issue was written while pull request #6 allocated only R9101 through
R9110. Its merged form also used R9111 for prefer-type-statement.
Preserving this issue's explicit R9111 acceptance contract therefore requires
renumbering that existing refactor message to R9112.

DataclassSlotsChecker.__init__ carries typing.override. The name is bound
through a TYPE_CHECKING branch so type checkers resolve it precisely, while
the runtime fallback keeps the plugin importable under the PyPy 3.11 pylint
shim that the project's own lint gate uses, where typing.override is absent.

References

leynos added 3 commits July 27, 2026 12:29
Add binding-aware recognition and conservative safety analysis for
standard-library dataclasses whose instance layout can be closed safely.
Cover open-state evidence, class identity hazards, and inherited layouts
with example, property, plug-in, and PyPy shim tests.

Reserve `R9111` for the issue's new rule and move the existing
`prefer-type-statement` refactor message to `R9112`.
Explain the literal slots requirement, evidence-based safety exemptions,
and explicit compatibility suppression path. Record the binding,
decorator-order, and cached layout analysis used by the checker.

Update the public inventory to thirteen messages and identify the
renumbered type-statement rule as `R9112`.
Treat fields from the full inherited lineage as declared state, so safe
grandparent-field assignments remain eligible for generated slots.

Classify manual slots from Astroid's resolved layout rather than from the
presence of an assignment, keeping multiple empty-slot marker bases
layout-neutral.
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary

  • Add prefer-slots-for-dataclass (R9111) for closed standard-library dataclasses.
  • Resolve dataclass decorators through scope-aware imports and aliases.
  • Report missing literal slots=True or local __slots__ at the decorator.
  • Suppress reports for unsafe, ambiguous, or incompatible layouts.
  • Distinguish dataclass fields from class-only names and preserve inherited dictionaries.
  • Register the checker and update documentation, migration guidance, and message inventories.
  • Document the design in ADR 001.
  • Renumber prefer-type-statement from R9111 to R9112.
  • Constrain Pylint to versions >=3.3 and <5.
  • Add unit, safety, property, performance, plugin, and end-to-end coverage.
  • Implement the requirements from issue #11.
  • Pass repository validation and property/model checks.

Walkthrough

Add the prefer-slots-for-dataclass checker with conservative decorator, state, inheritance, and inference analysis. Register R9111, renumber prefer-type-statement to R9112, and add tests, documentation, migration guidance, and Pylint version bounds.

Changes

Dataclass slots checker

Layer / File(s) Summary
Resolve dataclasses and instance state
df12_python_lints/_dataclass_decorators.py, df12_python_lints/_dataclass_inference.py, df12_python_lints/_dataclass_state.py
Resolve standard-library dataclass decorators. Identify fields, explicit slots, inherited state, and inferred base classes.
Analyse slot-layout safety
df12_python_lints/_dataclass_analysis.py
Suppress reports for open state, decorator hazards, unsafe inheritance, layout conflicts, variable-length bases, and inference ambiguity. Cache recursive eligibility decisions.
Register and emit R9111
df12_python_lints/dataclass_slots.py, df12_python_lints/__init__.py, df12_python_lints/type_aliases.py, pyproject.toml
Register and export DataclassSlotsChecker. Emit R9111. Use R9112 for prefer-type-statement. Constrain Pylint to versions below 5.
Validate and document the rule
tests/dataclass_slots_support.py, tests/test_dataclass_slots.py, tests/test_dataclass_slots_safety.py, tests/test_dataclass_slots_class_cells.py, tests/test_dataclass_slots_performance.py, tests/test_dataclass_slots_layout.py, tests/test_properties.py, tests/test_plugin.py, tests/test_e2e_shim.py, README.md, docs/*
Cover reporting, suppression, inference, performance, property cases, registration, end-to-end fixtures, message inventories, migration guidance, and rule documentation.

Sequence Diagram(s)

sequenceDiagram
  participant Pylint
  participant DataclassSlotsChecker
  participant DataclassDecoratorResolver
  participant LayoutAnalyzer
  Pylint->>DataclassSlotsChecker: visit class
  DataclassSlotsChecker->>DataclassDecoratorResolver: resolve decorator
  DataclassDecoratorResolver-->>DataclassSlotsChecker: dataclass and slots value
  DataclassSlotsChecker->>LayoutAnalyzer: evaluate layout safety
  LayoutAnalyzer-->>DataclassSlotsChecker: eligibility result
  DataclassSlotsChecker-->>Pylint: emit R9111 when eligible
Loading

Suggested labels: Issue

Poem

Dataclass fields align,
Slots close the state in line.
R9111 marks the way,
R9112 keeps aliases clear.
Tests guard each boundary,
Docs record the rule precisely.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 warning, 3 inconclusive)

Check name Status Explanation Resolution
Performance And Resource Use ⚠️ Warning Flag the quadratic path: each eligible class rebuilds declared_instance_state() by walking all ancestors, while the performance test counts only _local_layout() calls. Cache inherited state per class or compute it during layout analysis, then add a deep-chain regression check for state-walk count or bounded runtime.
Developer Documentation ❓ Inconclusive Evidence gathering is still in progress. Inspect the implemented APIs and repository planning documents before deciding whether the developer documentation is complete.
Unit Architecture ❓ Inconclusive Investigation is still in progress; no verdict submitted yet. Continue source and test inspection before deciding.
Domain Architecture ❓ Inconclusive Initial inspection shows analysis code tightly coupled to Astroid and the Pylint framework, but this repository's domain is itself a Pylint plugin; confirm its intended boundaries first. Inspect package architecture, dependency declarations, and existing checker patterns before deciding whether Astroid coupling violates this check.
✅ Passed checks (16 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Testing (Overall) ✅ Passed Accept: 1,200+ added test lines cover diagnostics, aliases, state, safety, inheritance, inference, caching, integration, and clean/violating end-to-end fixtures with exact assertions.
User-Facing Documentation ✅ Passed The user guide documents R9111, recognised forms, reporting and suppression cases, manual slots, diagnostics, and migration guidance.
Module-Level Documentation ✅ Passed AST audit found a module docstring in every Python module; the new dataclass modules state their purpose, utility, and relationship to DataclassSlotsChecker.
Testing (Unit And Behavioural) ✅ Passed Accept the check: focused tests cover reporting, suppression, edge and failure paths; plugin tests verify registration; shim tests exercise real violation and clean-module Pylint workflows.
Testing (Property / Proof) ✅ Passed The PR adds a substantive Hypothesis property over dataclass keyword order and slot values, and retains bounded CrossHair checks with explicit postconditions.
Testing (Compile-Time / Ui) ✅ Passed The repository contains only Python, so Rust/TypeScript compile-time tests do not apply. Pylint output has focused MessageTest and exact semantic contract assertions; snapshots would add brittle fo...
Observability ✅ Passed PASS: This change adds a synchronous Pylint checker that only emits diagnostics; it introduces no service, network, storage, or async boundary requiring logs, metrics, tracing, or alerts.
Security And Privacy ✅ Passed Keep the change: the new code performs static Astroid analysis, has no secret handling or privileged operations, and emits only the dataclass name in diagnostics; added scans found no credentials o...
Concurrency And State ✅ Passed Keep this design: LayoutAnalyzer owns private per-module caches, visit_module resets them, Pylint parallel work uses isolated processes and serial AST walks, and exception cleanup is tested.
Architectural Complexity And Maintainability ✅ Passed Accept the architecture: private modules separate real AST concerns, LayoutAnalyzer has an immediate cache use, docs justify resolver differences, the graph has no cycles, and no dependency was added.
Rust Compiler Lint Integrity ✅ Passed PASS: The repository and pull request contain no Rust sources, Cargo files, Rust lint suppressions, or Rust clone patterns; the change is Python-only.
Description check ✅ Passed Accept the description because it clearly explains the checker, safety rules, message renumbering, tests, documentation, and validation.
Linked Issues check ✅ Passed Accept the linkage because the title and description reference issue #11, and the changes directly implement its stated requirements.
Out of Scope Changes check ✅ Passed Accept the scope because the implementation, tests, documentation, migration guidance, and message renumbering directly support the stated objectives.
Title check ✅ Passed Accept the title because it describes the main dataclass-slots change and links issue #11 as required.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-11-add-r9111-to-prefer-slots-for-closed-dataclass-value-types

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @LodyAI[bot], you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

codescene-access[bot]

This comment was marked as outdated.

Extract the open-state, class-hazard, and reverse-inheritance decisions
into focused helpers. This preserves the conservative checker behaviour
while keeping the new analysis within the repository's complexity
thresholds.
codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos marked this pull request as ready for review July 27, 2026 19:54

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

chatgpt-codex-connector[bot]

This comment was marked as resolved.

Restrict declared instance state to real dataclass fields and explicit
slots, and require manual slot declarations to have a runtime value.

Preserve inherited dictionaries through generated-slot bases and limit
reverse multiple-inheritance suppression to genuinely conflicting slot
lineages.
codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Jul 31, 2026

Copy link
Copy Markdown
Owner

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

@buzzybee-df12

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added the Issue label Aug 1, 2026
coderabbitai[bot]

This comment was marked as resolved.

Preserve conservative layout and import-resolution behaviour while fixing
the review findings around declared state, generic extension bases,
inheritance, recursive analysis, and manual slots.

Strengthen diagnostic tests, document the 0.2.0 message migration, and bind
Pylint to the supported major-version range.
codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 2, 2026

Copy link
Copy Markdown
Owner

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

@coderabbitai coderabbitai Bot added the Roadmap label Aug 2, 2026
coderabbitai[bot]

This comment was marked as resolved.

Inspect nested executable scopes for replacement-class closures and treat
`typing_extensions` ClassVar and Protocol imports like their standard-library
counterparts.

Document the extracted inference helper and strengthen message-ID coverage.
codescene-access[bot]

This comment was marked as outdated.

@coderabbitai coderabbitai Bot removed the Roadmap label Aug 3, 2026
Memoize local inherited-layout classifications per module and clear the
provisional cache before final eligibility analysis. Add a structural scaling
regression for deep single-inheritance chains.

Record the conservative analysis and Pylint compatibility decisions in ADR
001 and link them from the developer documentation.
coderabbitai[bot]

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

Use the project Oxford spelling required by the documentation gate.
codescene-access[bot]

This comment was marked as outdated.

Stop class-cell scans at nested class boundaries and consume at most two
inference candidates when deciding ambiguity.

Add focused regressions for nested helper classes and unbounded inference
streams.
codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 3, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Have the following now been resolved?

df12_python_lints/_dataclass_analysis.py (1)

188-195: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Stop the scan at nested class boundaries.
nodes_of_class((nodes.Name, nodes.Call)) traverses nested ClassDef bodies. A local helper class using zero-argument super() can therefore suppress R9111 for its outer dataclass. Pass skip_klass=nodes.ClassDef and add a regression test.

🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @df12_python_lints/_dataclass_analysis.py around lines 188 - 195, Update
_uses_class_cell to exclude nested class bodies while scanning for class
names and zero-argument super() calls by passing skip_klass=nodes.ClassDef to
nodes_of_class. Add a regression test covering a nested helper class with
zero-argument super() and verify it does not suppress R9111 for the outer
dataclass.

Source: MCP tools

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- target file outline ---'
ast-grep outline df12_python_lints/_dataclass_analysis.py --items all --match 'uses_class_cell|class_cell' || true

echo '--- class-cell helper implementation ---'
rg -n -A35 -B8 'def _uses_class_cell\b|nodes_of_class\(' df12_python_lints/_dataclass_analysis.py

echo '--- relevant test locations ---'
rg -n -A18 -B6 'nested.*class|helper.*class|zero-argument.*super|super\(\)' tests/test_dataclass_slots_safety.py tests/test_dataclass_slots.py tests/dataclass_slots_support.py || true

echo '--- changed files and target diff ---'
git diff --name-only HEAD~1..HEAD || true
git diff HEAD~1..HEAD -- df12_python_lints/_dataclass_analysis.py tests/test_dataclass_slots_safety.py tests/test_dataclass_slots.py || true

Length of output: 12379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- safety tests around class-cell handling ---'
sed -n '120,185p' tests/test_dataclass_slots_safety.py

echo '--- assertion helpers ---'
sed -n '1,120p' tests/dataclass_slots_support.py

echo '--- all nested ClassDef declarations in dataclass-slots tests ---'
rg -n -U -P '^\s+class\s+\w+:[\s\S]{0,500}?\bsuper\s*\(\s*\)' \
  tests/test_dataclass_slots.py tests/test_dataclass_slots_safety.py || true

echo '--- helper-class names and report assertions ---'
rg -n -i -C4 'class\s+(helper|local|inner)|assert_reports\(' \
  tests/test_dataclass_slots.py tests/test_dataclass_slots_safety.py

Length of output: 15315


@leynos: Do not mark this finding fully resolved.

_uses_class_cell now passes skip_klass=nodes.ClassDef to nodes_of_class at df12_python_lints/_dataclass_analysis.py:185-187. This change prevents a nested helper class from suppressing R9111 for its outer dataclass.

The required regression test is absent. tests/test_dataclass_slots_safety.py:156-172 covers a nested function with zero-argument super(). That case must remain silent. It does not cover a nested helper class.

Add a test that uses self.assert_reports(...) for an unslotted outer Record dataclass with a method that defines a nested Helper class that calls super(). Assert that Record reports prefer-slots-for-dataclass.

I could not run validation in this sandbox.

You are interacting with an AI system.

@leynos

leynos commented Aug 3, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Have the following failed checks now been resolved?

If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures.

Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already. (Treat documentation and validation coverage as in scope).

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Performance And Resource Use ⚠️ Warning inferred_class materializes every base.infer() result, and _local_layout recursively recomputes ancestor layouts without a layout cache, causing avoidable memory use and O(depth²) chains. Bound inference to two candidates and memoize each class layout; add long-inheritance-chain and high-ambiguity regression or benchmark coverage.

@coderabbitai

This comment was marked as resolved.

leynos added 2 commits August 3, 2026 16:35
Require manual `__slots__` declarations to resolve unambiguously to a
complete valid slot value before suppressing R9111.

Use the validated names for inherited layout and declared-state analysis,
and document and test the rejected annotation-only, invalid, unresolved,
and ambiguous forms.
Split inferred value classification from element validation so each helper
has one decision level while preserving the conservative R9111 behaviour.
codescene-access[bot]

This comment was marked as outdated.

Add terminal bare returns to the checker lifecycle methods and narrowly
suppress the conflicting redundant-return rules where necessary.
codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 3, 2026

Copy link
Copy Markdown
Owner

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

coderabbitai[bot]

This comment was marked as resolved.

A manual `__slots__` entry naming `__dict__` keeps the instance dictionary
alive, so the layout is not closed. Classify such a layout as `Layout.UNSAFE`
before it can be read as `SLOTTED`, which stops R9111 firing on a dataclass
child of a local base that declares `__slots__ = ("__dict__",)`.

Mark `DataclassSlotsChecker.__init__` with `typing.override`, keeping the
existing `disable-next` comment immediately before the `def` so it still
applies. The name is bound through a `TYPE_CHECKING` branch: type checkers see
`typing.override` precisely, while the runtime fallback keeps the plugin
importable under the PyPy 3.11 pylint shim, where `typing.override` is absent.

Rewrite the ADR decision statement impersonally, and correct the developer
guide's account of the replacement-class scan: it enters nested executable
scopes but stops at nested `ClassDef` bodies, since a nested helper class owns
its own class cell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as resolved.

leynos added 2 commits August 8, 2026 12:49
Accept the `LayoutAnalyzer` identifier and literal external API terms so
the generated spelling configuration validates the documentation.
codescene-access[bot]

This comment was marked as outdated.

Reuse each class's declared state while analysing local inheritance so
deep dataclass chains avoid repeated ancestor walks.
@leynos

leynos commented Aug 11, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Have the following failed checks now been resolved?

If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures.

Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already. (Treat o11y, code safety, documentation and validation coverage as in scope).

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Performance And Resource Use ⚠️ Warning Flag the quadratic path: each eligible class rebuilds declared_instance_state() by walking all ancestors, while the performance test counts only _local_layout() calls. Cache inherited state per class or compute it during layout analysis, then add a deep-chain regression check for state-walk count or bounded runtime.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- relevant file discovery ---'
fd -t f . df12_python_lints tests docs | rg '(_dataclass_(state|analysis)\.py$|dataclass_slots\.py$|test_dataclass_slots_(performance|safety|layout)\.py$|dataclass_slots_support\.py$|developers-guide\.md$|adr-001)'

echo '--- module outlines ---'
ast-grep outline df12_python_lints/_dataclass_state.py --items all --view expanded
ast-grep outline df12_python_lints/_dataclass_analysis.py --items all --match 'LayoutAnalyzer|state|layout' --view expanded
ast-grep outline df12_python_lints/dataclass_slots.py --items all --view expanded
ast-grep outline tests/test_dataclass_slots_performance.py --items all --view expanded

echo '--- state aggregation definitions and call sites ---'
rg -n -A45 -B10 \
  'def (declared_instance_state|dataclass_field_names|local_slot_names|has_declared_instance_fields)\b|\bdeclared_instance_state\s*\(' \
  df12_python_lints tests

echo '--- layout cache and eligibility path ---'
rg -n -A80 -B12 \
  '_local_layout|_base_layout|_layout_cache|is_eligible|has_declared_instance_fields|declared_instance_state' \
  df12_python_lints/_dataclass_analysis.py df12_python_lints/dataclass_slots.py

echo '--- performance regression coverage ---'
cat -n tests/test_dataclass_slots_performance.py

echo '--- current PR diff for relevant paths ---'
git diff "$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main 2>/dev/null || echo HEAD~1)" HEAD -- \
  df12_python_lints/_dataclass_state.py \
  df12_python_lints/_dataclass_analysis.py \
  df12_python_lints/dataclass_slots.py \
  tests/test_dataclass_slots_performance.py \
  docs/developers-guide.md \
  docs/adr-001-conservative-dataclass-layout-analysis.md || true

Length of output: 84469


@leynos: Mark this warning resolved.

LayoutAnalyzer now owns the per-module _declared_states cache in df12_python_lints/_dataclass_analysis.py:299.

LayoutAnalyzer.is_eligible() passes this cache into has_local_slots_hazard() at Line 396. That function passes the cache into declared_instance_state() at Line 251.

declared_instance_state() now caches the complete visible state for each ClassDef in df12_python_lints/_dataclass_state.py:147-160. A later class reuses cached ancestor state instead of rebuilding local state for every eligible descendant.

tests/test_dataclass_slots_performance.py::test_deep_layout_chain_resolves_state_once_per_class provides the required regression coverage. It creates an 80-class inheritance chain, counts _local_instance_state() calls, and requires a linear bound of depth + 1.

No remaining work exists. Do not create a follow-up issue. No AI agent prompt is required.

Repository test execution was unavailable in this sandbox.

You are interacting with an AI system.

@leynos
leynos merged commit 9c835f3 into main Aug 11, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add R9111 to prefer slots for closed dataclass value types

2 participants