Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙️ Pengaturan Proxy Target

Skip to content

[ty] Avoid writable override contracts from object - #29373

Merged
carljm merged 1 commit into
mainfrom
cjm/fix-4725-module-override
Oct 14, 2026
Merged

carljm merged 1 commit into
mainfrom
cjm/fix-4725-module-override

Conversation

@carljm

@carljm carljm commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Fix false invalid-mutable-override diagnostics when slotted classes assign metadata such as __module__. The attributes declared on object do not establish an instance-write contract for subclasses, because object provides no instance attribute storage. Read-type compatibility and write contracts explicitly declared by user-defined bases remain checked.

Fixes astral-sh/ty#4725.

Test plan

Checked CPython 3.13 behavior: assignments to __module__, __doc__, __annotations__, __dict__, and __str__ on object() fail. Also verified that __class__ assignment fails for object() but can succeed between compatible slotted user-defined classes.

Ecosystem report

Analyzed head: 56847d246246b4381d4873a36495e0d91d89f469. The ecosystem shows 23 expected false-positive removals across eight projects: getter-only metadata properties and metadata assignments in slotted class bodies. All changes are intended, with no ecosystem concerns remaining. Full report.

@carljm carljm added bug An issue describing something that isn't working, or a PR that fixes a bug ty The ty type checker labels Oct 14, 2026
@astral-sh-bot

astral-sh-bot Bot commented Oct 14, 2026

Copy link
Copy Markdown

Memory usage report

Memory usage unchanged ✅

@astral-sh-bot

astral-sh-bot Bot commented Oct 14, 2026

Copy link
Copy Markdown

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 98.24%. The percentage of expected errors that received a diagnostic held steady at 98.24%. The number of fully passing files held steady at 134/146.

@astral-sh-bot

astral-sh-bot Bot commented Oct 14, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-property-type-override 0 12 0
invalid-mutable-override 0 11 0
Total 0 23 0
Raw diff (23 changes)
dd-trace-py (https://github.com/DataDog/dd-trace-py)
- ddtrace/contrib/internal/django/utils.py:453:9 error[invalid-property-type-override] Invalid override of attribute `__module__`: Read-only attribute overrides a writable attribute

egglog-python (https://github.com/egraphs-good/egglog-python)
- python/egglog/runtime.py:458:9 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute
- python/egglog/runtime.py:620:9 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute

psycopg (https://github.com/psycopg/psycopg)
- psycopg/psycopg/_wrappers.py:19:5 error[invalid-mutable-override] Invalid override of attribute `__module__`: Override does not accept writes of type `str`
- psycopg/psycopg/_wrappers.py:37:5 error[invalid-mutable-override] Invalid override of attribute `__module__`: Override does not accept writes of type `str`
- psycopg/psycopg/_wrappers.py:55:5 error[invalid-mutable-override] Invalid override of attribute `__module__`: Override does not accept writes of type `str`
- psycopg/psycopg/_wrappers.py:73:5 error[invalid-mutable-override] Invalid override of attribute `__module__`: Override does not accept writes of type `str`
- psycopg/psycopg/_wrappers.py:91:5 error[invalid-mutable-override] Invalid override of attribute `__module__`: Override does not accept writes of type `str`
- psycopg/psycopg/_wrappers.py:109:5 error[invalid-mutable-override] Invalid override of attribute `__module__`: Override does not accept writes of type `str`
- psycopg/psycopg/_wrappers.py:127:5 error[invalid-mutable-override] Invalid override of attribute `__module__`: Override does not accept writes of type `str`

scipy (https://github.com/scipy/scipy)
- scipy/special/_multiufuncs.py:60:9 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute

scipy-stubs (https://github.com/scipy/scipy-stubs)
- scipy-stubs/special/_multiufuncs.pyi:49:9 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute

sympy (https://github.com/sympy/sympy)
- sympy/multipledispatch/dispatcher.py:320:9 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute
- sympy/assumptions/assume.py:185:9 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute
- sympy/core/cache.py:186:13 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute
- sympy/core/cache.py:200:13 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute
- sympy/core/kind.py:344:9 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute
- sympy/core/operations.py:708:9 error[invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute
- sympy/core/relational.py:1522:5 error[invalid-mutable-override] Invalid override of attribute `__doc__`: Override does not accept writes of type `str | None`
- sympy/core/relational.py:1539:5 error[invalid-mutable-override] Invalid override of attribute `__doc__`: Override does not accept writes of type `str | None`
- sympy/core/relational.py:1557:5 error[invalid-mutable-override] Invalid override of attribute `__doc__`: Override does not accept writes of type `str | None`

xarray (https://github.com/pydata/xarray)
- xarray/plot/accessor.py:39:5 error[invalid-mutable-override] Invalid override of attribute `__doc__`: Override does not accept writes of type `str | None`

zope.interface (https://github.com/zopefoundation/zope.interface)
- src/zope/interface/tests/test_interface.py:364:17 error[invalid-property-type-override] Invalid override of attribute `__module__`: Read-only attribute overrides a writable attribute

Full report with detailed diff (timing results)

@carljm
carljm marked this pull request as ready for review October 14, 2026 16:22
@carljm
carljm requested a review from a team as a code owner October 14, 2026 16:22
@astral-sh-bot
astral-sh-bot Bot requested a review from sharkdp October 14, 2026 16:22
@carljm

carljm commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author
Ecosystem report

PR #29373 ecosystem summary

The PR removes 23 false-positive override diagnostics across eight projects. Two patterns account for the changes: getter-only properties that expose class metadata, and metadata assignments in slotted class bodies. Neither pattern needs to preserve instance writes that object does not provide. All retained changes are intended.

Analyzed PR head: 56847d246246b4381d4873a36495e0d91d89f469.

Diagnostic changes (2 sections)

1. Getter-only metadata properties

12 removed invalid-property-type-override diagnostics.

Report entries

Egglog, SciPy, scipy-stubs, and SymPy expose computed documentation through getter-only __doc__ properties. The merge base incorrectly required these properties to preserve a writable attribute inherited from object. The PR removes that write requirement while retaining read-type compatibility.

Reduced from SciPy’s MultiUFunc:

class MultiUFunc:
    @property
    # Merge base: [invalid-property-type-override] Invalid override of attribute `__doc__`: Read-only attribute overrides a writable attribute
    # PR: no diagnostic
    def __doc__(self):
        ...

DjangoViewProxy forwards a wrapped callable’s module through a __module__ property. Zope’s comparison tests use the same property shape with a getter that raises AttributeError to simulate missing metadata. The getter implementation is incidental to the incorrect inherited write requirement.

Reduced from dd-trace-py’s DjangoViewProxy:

class DjangoViewProxy:
    @property
    # Merge base: [invalid-property-type-override] Invalid override of attribute `__module__`: Read-only attribute overrides a writable attribute
    # PR: no diagnostic
    def __module__(self):
        ...

2. Metadata assignments in slotted class bodies

11 removed invalid-mutable-override diagnostics.

Report entries

Psycopg gives seven numeric wrapper classes a public module name through __module__. Their empty slots prevent arbitrary instance writes but do not prevent class-body assignments. The numeric base classes and wrapper methods are unnecessary to reproduce the false positive.

Reduced from Psycopg’s numeric wrappers:

class NumericWrapper:
    # Merge base: [invalid-mutable-override] Invalid override of attribute `__module__`: Override does not accept writes of type `str`
    # PR: no diagnostic
    __module__ = "psycopg.types.numeric"
    __slots__ = ()

Xarray’s plotting accessor copies a plotting function’s documentation, and three SymPy comparison classes copy another comparison class’s documentation. These class-body assignments are likewise valid without writable instance storage. The particular documentation value is not essential to the error.

Reduced from Xarray’s plotting accessor:

class PlotAccessor:
    __slots__ = ()
    # Merge base: [invalid-mutable-override] Invalid override of attribute `__doc__`: Override does not accept writes of type `str | None`
    # PR: no diagnostic
    __doc__ = None

Reproduction

Details
  • Detailed report: ecosystem-analyzer report
  • Actions run: run 38593385669, attempt 1
  • Ruff comparison: 523d83c941cbae9b7c8a10739c839a8eeda3245d to Actions merge revision 64dbc409b75573ac2c84c76449eab2713fa04685
  • ecosystem-analyzer: ebec9bd301f36aa1308fc2e0c743129ff23581fc
  • mypy-primer: e1f6fe93da5de0cbaf0ab00341d05968a0331fae
  • Dependency cutoff: 2026-10-14T15:53:58Z
  • Project Python: Python 3.11.17 for all eight project environments. Effective targets: dd-trace-py 3.9; egglog-python, SciPy, scipy-stubs, and Xarray 3.12; Psycopg, SymPy, and zope.interface 3.11.
  • Python target platform: all for scipy-stubs; linux for the other seven projects.
  • Execution environment: Ubuntu 24.04 x86_64 containers, using the exact CI profiling binaries and uv 0.13.1. Checker environment preserved TY_UV=scripts, UV_LOCKED=1, RUST_BACKTRACE=1, UV_PYTHON=3.13, the recorded SQLAlchemy constraint, UV_NO_BUILD=1, and UV_NO_BINARY=0. Containers ran under x86_64 emulation on an ARM64 Docker host; CI used native x86_64 runners.
  • Checker deadline: 180 seconds, matching the analyzer’s default dev profile despite its prebuilt profiling binaries.
  • Project analysis mode: strict for Xarray and zope.interface; non-strict for the other six projects.
  • Comparison method: ran each project’s original command with each exact-revision binary, its Python environment, and the ecosystem configuration installed as user-level configuration. Strict projects additionally used --config analysis.strict-equality-semantics=true --config analysis.strict-generic-narrowing=true. Minimized cases retained their original target version, platform, and strictness settings.

@sharkdp sharkdp left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you.

Should this maybe be fixed in typeshed? Could object.__module__ be defined as a read-only property returning str? Or would that imply something beyond "has a read type of str"?

read,
write: if is_final || !is_class_var && literal.is_frozen_dataclass(db) == Some(true) {
// `object` provides no instance attribute storage, so its declarations impose
// no write contract on subclasses.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I looked at this PR before looking at the issue and had trouble understanding both the PR summary and this comment (it makes sense now with more context, but in isolation, I didn't understand). You wrote a nice explanation of the problem here. I think it would make for a better source comment here. Maybe also prefix it with "attributes on object are included here, because ..." to make it clear that the comment only refers to the first condition in the OR chain.

Comment on lines +3716 to +3718
`object` does not provide writable instance attributes. Its attribute declarations constrain read
types, but do not require subclasses to support instance writes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I feel like this should maybe mention typeshed's object definition? Something like

typeshed declares attributes like __module__: str on the class object. Usually, this indicates the presence of a writable instance attribute...

@carljm

carljm commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Should this maybe be fixed in typeshed? Could object.__module__ be defined as a read-only property returning str? Or would that imply something beyond "has a read type of str"?

It's tricky because it's reasonable for a type checker to also take that to mean "class access returns a property object". This kind of thing is the motivation for https://peps.python.org/pep-0767/ - if we get that, then I think it should definitely be applied to these attributes of object.

@AlexWaygood

Copy link
Copy Markdown
Member

On this PR branch, we now do not emit any errors on this:

def f(x: object):
    x.__module__ = "foo"


class Bar:
    @property
    def __module__(self) -> str:
        return "foo"

f(Bar())

If we say that the Bar.__module__ override is acceptable, surely that means we must start rejecting the x.__module__ write?

@carljm

carljm commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

@AlexWaygood That's a good catch, but this particular unsound combination (allowing non-writable overrides of __module__ but also allowing writes to __module__ on object) puts us in the same boat as every other type checker. I'd prefer to land this change as-is (since it fixes a Liskov false-positive regression we clearly need to fix regardless) and then evaluate the ecosystem impact of fixing this soundness gap (with stricter validation of writes to object attributes) separately.

@carljm
carljm merged commit 355b42a into main Oct 14, 2026
76 checks passed
@carljm
carljm deleted the cjm/fix-4725-module-override branch October 14, 2026 18:59
@carljm

carljm commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Ugh shoot I then also forgot to push my wording updates to address @sharkdp comments. Will put up a separate PR for that too 😆

This branch was previously deployed

1 inactive deployment
automations — 56847d24 Deployed Oct 14, 2026 by carljm via security-review / security review #91718
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug An issue describing something that isn't working, or a PR that fixes a bug ty The ty type checker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

invalid-mutable-override on __module__ in a class body when a base class has __slots__

3 participants