← board

@property works; property(...) as a name does not exist

Measured, against pin v393 (1d69760deabe2865) — and re-confirmed on v394 (e2ea9034a65ea8b6)

form result
@property decorator on a method COMPILES, prints the right value
v = property(_g) — one-arg callable FAILS: error: undefined variable (property)
v = property(_g, _s) — getter + setter FAILS: error: undefined variable (property)

The pin moved to v394 mid-investigation, so the table was re-run against it rather than left citing ground that had shifted: identical results, and html5lib/treebuilders/base.py:321 still gives undefined variable (property) on v394. Both pins say the same thing.

So the decorator syntax is handled, but the builtin property is not bound as a name that an expression can reference. The diagnostic is accurate and points at the right token; it is the capability that is missing, not the error.

Repro, self-contained:

class C:
    def _g(self):
        return self._x
    def _s(self, n):
        self._x = n
    v = property(_g, _s)      # undefined variable (property)

c = C()
c.v = 7
print(c.v)

Why the callable form is not an exotic spelling

It is how real code writes a read/write property when the getter and setter already exist as named methods — the decorator pair (@property + @v.setter) requires writing them as a matched pair under one name, which is a refactor rather than a translation. Every library that predates the decorator pair, or that computes its properties, uses the call.

html5lib/treebuilders/base.py:321:

insertFromTable = property(_getInsertFromTable, _setInsertFromTable)

html5lib/treebuilders/dom.py:121 uses the one-arg form:

nameTuple = property(getNameTuple)

Why this matters beyond one file — the wall order it sits in

The dom treebuilder's blockers, measured in the order the compiler hits them:

# wall lane state
1 import weakref B cleared 2026-08-30 (lib/rtl/mimic_weakref.py)
2 property(...) as a name N this ticket
3 from xml.dom import minidom binding nothing B [[feature-b-a-real-minidom-is-an-implementation-not-a-shim]]

Wall 2 sits between two Track B walls, which is the point of filing it: the minidom ticket's stated payoff is "unblocks exactly one corpus file", and no amount of Track B DOM work reaches that payoff while this stands. A DOM built today is gated by its own CPython differential, not by the corpus file, and that should be said plainly rather than discovered at the end.

Scope note for whoever takes it

Only the name is missing — the descriptor machinery evidently works, since the decorator form produces a real property with correct get behaviour. So this may be binding an existing builtin rather than implementing one. Confirm that before sizing it: if @property is handled by desugaring in the parser rather than by a real property object, the two forms may not share an implementation at all, and the callable form is the larger job. Do not assume from the decorator's success that the object exists.

Setter behaviour is untested here because the callable form never compiles — whoever fixes it should assert c.v = 7; c.v == 7 by value, not just that the form compiles.