Skip to content

PyClass has no decorators field — class decorators are silently dropped #127

Description

@rahlk

Problem

PyClass (codeanalyzer/schema/py_schema.py) has no decorators field. PyCallable
has one (py_schema.py:274, filled at syntactic_analysis/symbol_table_builder.py:334),
but the class branch of the builder never reads ClassDef.decorator_list, so every class
decorator is dropped silently — no field, no warning.

Verified on main (6f02581) against a fixture with @dataclass class Account:

CLASS 'app.Account' (has 'decorators' key? False)
method 'doubled' decorators=['property']

The methods carry theirs; the class carries nothing. This loses @dataclass,
@app.errorhandler, Django/pydantic class decorators, and @pytest.mark.* on test
classes — the decorators that classify what a class is.

Scope boundary

Adds decorators: List[str] to PyClass and populates it, mirroring how PyCallable
already works. Does not resolve decorator strings to ids (#128), does not
touch call-graph edges (#129), and does not add any new node type.

Goals

  • PyClass.decorators: List[str] = [], unparsed source strings in source order
  • Populated for top-level and nested/inner classes
  • Neo4j: reuse the existing :PyDecorator node and PY_DECORATED_BY relationship,
    widening its start label from ["PyCallable"] to include PyClass
    (neo4j/schema.py:237), plus the flat decorators: string[] property
  • Bump Neo4j SCHEMA_VERSION (additive)

Caveats and known risks

  • Schema v2 change, so it enters at designing-cldk-changes, not a patch. It is
    purely additive (new optional field, defaults to []), so the monotonicity gate and
    every existing consumer are unaffected.
  • Sibling analyzers share the vocabulary. TypeScript has class decorators too;
    whatever name and shape lands here should be the canonical one, not a Python rename.
  • Available from L1 (it is symbol-table data), so it must not be gated behind a level.

Definition of done

  • The fixture above emits decorators: ["dataclass"] on app.Account
  • An inner class with a decorator emits it too
  • A class with no decorators emits [], not a missing key
  • analysis.json(-a 1) ⊆ ... ⊆ (-a 4) still holds
  • Neo4j PY_DECORATED_BY traverses from a :PyClass node

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions