Skip to content

Conversation

sharkdp
Copy link
Contributor

@sharkdp sharkdp commented Oct 10, 2025

Summary

Treat Callables as bound-method descriptors if Callable is the return type of a decorator that is applied to a function definition. See the rendered version of the new test file for the full description of this new heuristic.

I could imagine that we want to treat Callables as bound-method descriptors in other cases as well, but this seems like a step in the right direction. I am planning to add other "use cases" from astral-sh/ty#491 to this test suite.

partially addresses astral-sh/ty#491
closes astral-sh/ty#1333

Ecosystem impact

All positive

  • 2961 removed unsupported-operator diagnostics on sympy, which was one of the main motivations for implementing this change
  • 37 removed missing-argument diagnostics, and no added call-error diagnostics, which is an indicator that this heuristic shouldn't cause many false positives
  • A few removed possibly-missing-attribute diagnostics when accessing attributes like __name__ on decorated functions. The two added unused-ignore-comment diagnostics are also cases of this.
  • One new invalid-assignment diagnostic on dd-trace-py, which looks suspicious, but only because our invalid-assignment diagnostics are not great. This is actually a "Implicit shadowing of function" diagnostic that hides behind the invalid-assignment diagnostic, because a module-global function is being patched through a module.func attribute assignment.

Test Plan

New Markdown tests.

@sharkdp sharkdp added ty Multi-file analysis & type inference ecosystem-analyzer labels Oct 10, 2025
Copy link
Contributor

github-actions bot commented Oct 10, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

Copy link
Contributor

github-actions bot commented Oct 10, 2025

mypy_primer results

Changes were detected when running on open source projects
pytest-robotframework (https://github.com/detachhead/pytest-robotframework)
+ pytest_robotframework/__init__.py:759:93: warning[unused-ignore-comment] Unused `ty: ignore` directive: 'unresolved-attribute'
- Found 169 diagnostics
+ Found 170 diagnostics

trio (https://github.com/python-trio/trio)
- src/trio/_deprecate.py:137:5: error[unresolved-attribute] Unresolved attribute `__qualname__` on type `(...) -> Unknown`.
- src/trio/_deprecate.py:138:5: error[unresolved-attribute] Unresolved attribute `__name__` on type `(...) -> Unknown`.
- Found 647 diagnostics
+ Found 645 diagnostics

pwndbg (https://github.com/pwndbg/pwndbg)
- pwndbg/commands/context.py:181:9: warning[possibly-missing-attribute] Attribute `__name__` on type `Unknown | ((...) -> list[str])` may be missing
- pwndbg/gdblib/tui/context.py:216:9: warning[possibly-missing-attribute] Attribute `__name__` on type `Unknown | ((...) -> list[str])` may be missing
- Found 2590 diagnostics
+ Found 2588 diagnostics

CPython (cases_generator) (https://github.com/python/cpython)
- Tools/cases_generator/parser.py:69:23: error[missing-argument] No argument provided for required parameter 1
- Tools/cases_generator/parsing.py:738:19: error[missing-argument] No argument provided for required parameter 1
- Found 9 diagnostics
+ Found 7 diagnostics

dd-trace-py (https://github.com/DataDog/dd-trace-py)
+ tests/debugging/probe/test_remoteconfig.py:69:9: error[invalid-assignment] Object of type `(...) -> Iterable[Probe]` is not assignable to attribute `get_probes` of type `(...) -> Iterable[Probe]`
- tests/internal/test_packages.py:28:30: error[unresolved-attribute] Type `(...) -> Unknown` has no attribute `__code__`

sympy (https://github.com/sympy/sympy)
- sympy/algebras/tests/test_quaternion.py:72:37: error[unsupported-operator] Operator `*` is unsupported between objects of type `MutableDenseMatrix` and `MutableDenseMatrix`
- sympy/algebras/tests/test_quaternion.py:73:37: error[unsupported-operator] Operator `*` is unsupported between objects of type `MutableDenseMatrix` and `MutableDenseMatrix`
- sympy/algebras/tests/test_quaternion.py:201:55: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[5]`
- sympy/algebras/tests/test_quaternion.py:201:69: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[5]`
- sympy/algebras/tests/test_quaternion.py:365:66: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[5]`
- sympy/algebras/tests/test_quaternion.py:365:80: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[5]`
- sympy/algebras/tests/test_quaternion.py:420:33: error[unsupported-operator] Operator `-` is unsupported between objects of type `MutableDenseMatrix` and `MutableDenseMatrix`
- sympy/assumptions/tests/test_query.py:2113:32: error[unsupported-operator] Operator `**` is unsupported between objects of type `MutableDenseMatrix` and `Literal[2]`
- sympy/assumptions/tests/test_query.py:2114:10: error[unsupported-operator] Operator `**` is unsupported between objects of type `MutableDenseMatrix` and `Literal[3]`
- sympy/assumptions/tests/test_refine.py:53:26: error[unsupported-operator] Operator `-` is unsupported between objects of type `int | float` and `Half`
- sympy/assumptions/tests/test_refine.py:54:26: error[unsupported-operator] Operator `+` is unsupported between objects of type `int | float` and `Half`
- sympy/assumptions/tests/test_refine.py:55:38: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[5]` and `Half`
- sympy/assumptions/tests/test_refine.py:59:38: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[7]` and `Half`
- sympy/assumptions/tests/test_refine.py:60:38: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[9]` and `Half`
- sympy/benchmarks/bench_symbench.py:17:21: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[3]`
- sympy/benchmarks/bench_symbench.py:99:21: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[10]`
- sympy/calculus/finite_diff.py:190:30: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `One | Unknown`
- sympy/calculus/tests/test_accumulationbounds.py:25:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `AccumulationBounds` and `Literal[1]`
- sympy/calculus/tests/test_accumulationbounds.py:26:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Literal[1]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:27:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:31:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `AccumulationBounds` and `Literal[1]`
- sympy/calculus/tests/test_accumulationbounds.py:32:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `Literal[1]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:33:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:39:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `AccumulationBounds` and `Infinity`
- sympy/calculus/tests/test_accumulationbounds.py:40:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `AccumulationBounds` and `Infinity`
- sympy/calculus/tests/test_accumulationbounds.py:41:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `AccumulationBounds` and `Infinity`
- sympy/calculus/tests/test_accumulationbounds.py:43:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `AccumulationBounds` and `Infinity`
- sympy/calculus/tests/test_accumulationbounds.py:45:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `AccumulationBounds` and `Infinity`
- sympy/calculus/tests/test_accumulationbounds.py:47:13: error[unsupported-operator] Operator `-` is unsupported between objects of type `Infinity` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:50:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:51:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[2]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:52:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[1]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:66:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:67:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[2]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:68:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:69:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:71:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:72:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:74:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:75:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:76:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `Literal[0]`
- sympy/calculus/tests/test_accumulationbounds.py:77:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `Literal[0]`
- sympy/calculus/tests/test_accumulationbounds.py:78:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `Literal[0]`
- sympy/calculus/tests/test_accumulationbounds.py:79:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `Literal[0]`
- sympy/calculus/tests/test_accumulationbounds.py:83:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `Infinity`
- sympy/calculus/tests/test_accumulationbounds.py:84:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `Infinity`
- sympy/calculus/tests/test_accumulationbounds.py:87:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `Infinity`
- sympy/calculus/tests/test_accumulationbounds.py:89:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `Infinity`
- sympy/calculus/tests/test_accumulationbounds.py:93:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:94:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:95:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:99:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:100:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:102:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:103:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:104:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:106:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:107:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:108:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:110:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[1]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:111:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[1]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:112:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[-1]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:113:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[1]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:114:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[1]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:115:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[-2]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:116:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[1]` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:120:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `AccumulationBounds` and `Literal[0]`
- sympy/calculus/tests/test_accumulationbounds.py:140:25: error[unsupported-operator] Operator `*` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:141:13: error[unsupported-operator] Operator `+` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:154:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:160:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:161:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:162:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:163:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[3]`
- sympy/calculus/tests/test_accumulationbounds.py:164:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[0]`
- sympy/calculus/tests/test_accumulationbounds.py:181:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-2]`
- sympy/calculus/tests/test_accumulationbounds.py:182:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-2]`
- sympy/calculus/tests/test_accumulationbounds.py:183:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-3]`
- sympy/calculus/tests/test_accumulationbounds.py:184:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-3]`
- sympy/calculus/tests/test_accumulationbounds.py:185:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-2]`
- sympy/calculus/tests/test_accumulationbounds.py:186:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-3]`
- sympy/calculus/tests/test_accumulationbounds.py:187:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-3]`
- sympy/calculus/tests/test_accumulationbounds.py:188:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-2]`
- sympy/calculus/tests/test_accumulationbounds.py:190:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-2]`
- sympy/calculus/tests/test_accumulationbounds.py:191:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `Literal[-2]`
- sympy/calculus/tests/test_accumulationbounds.py:234:34: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/calculus/tests/test_accumulationbounds.py:235:29: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/calculus/tests/test_accumulationbounds.py:239:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:239:23: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:240:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:243:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:243:36: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[27]`
- sympy/calculus/tests/test_accumulationbounds.py:243:45: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/calculus/tests/test_accumulationbounds.py:244:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:244:35: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[27]`
- sympy/calculus/tests/test_accumulationbounds.py:248:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:248:17: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:248:43: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:249:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:250:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:251:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:252:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:252:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:253:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:253:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:254:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:254:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:255:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:255:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:256:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:256:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:257:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:257:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:258:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:258:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:259:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:259:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:260:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:260:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:261:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:262:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:263:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:264:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:265:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:266:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:267:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:268:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_accumulationbounds.py:268:41: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_accumulationbounds.py:269:12: error[unsupported-operator] Operator `**` is unsupported between objects of type `AccumulationBounds` and `AccumulationBounds`
- sympy/calculus/tests/test_finite_diff.py:81:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `int` and `Integer`
- sympy/calculus/tests/test_util.py:184:18: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/calculus/tests/test_util.py:403:40: error[unsupported-operator] Operator `/` is unsupported between objects of type `Half` and `Literal[2]`
- sympy/calculus/tests/test_util.py:407:60: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/codegen/tests/test_algorithms.py:177:19: error[unsupported-operator] Operator `*` is unsupported between objects of type `Float` and `Unknown | float`
- sympy/codegen/tests/test_ast.py:536:13: error[unsupported-operator] Operator `+` is unsupported between objects of type `Float` and `complex`
- sympy/codegen/tests/test_cfunctions.py:139:45: error[unsupported-operator] Operator `-` is unsupported between objects of type `Rational` and `Literal[1]`
- sympy/codegen/tests/test_cfunctions.py:150:45: error[unsupported-operator] Operator `-` is unsupported between objects of type `Half` and `Literal[1]`
- sympy/codegen/tests/test_matrix_nodes.py:26:37: error[unsupported-operator] Operator `*` is unsupported between objects of type `MutableDenseMatrix` and `MutableDenseMatrix`
- sympy/codegen/tests/test_matrix_nodes.py:27:21: error[unsupported-operator] Operator `-` is unsupported between objects of type `MutableDenseMatrix` and `MutableDenseMatrix`
- sympy/codegen/tests/test_rewriting.py:430:21: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[58]` and `Integer`
- sympy/codegen/tests/test_rewriting.py:430:36: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[97]` and `Integer`
- sympy/codegen/tests/test_rewriting.py:430:51: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[4]` and `Integer`
- sympy/codegen/tests/test_rewriting.py:430:64: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[92]` and `Integer`
- sympy/concrete/tests/test_sums_products.py:346:52: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/concrete/tests/test_sums_products.py:572:42: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[10]`
- sympy/concrete/tests/test_sums_products.py:575:40: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[10]`
- sympy/concrete/tests/test_sums_products.py:1183:35: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[3]`
- sympy/concrete/tests/test_sums_products.py:1569:44: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/concrete/tests/test_sums_products.py:1571:39: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/concrete/tests/test_sums_products.py:1579:9: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/concrete/tests/test_sums_products.py:1587:27: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/concrete/tests/test_sums_products.py:1594:70: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/concrete/tests/test_sums_products.py:1595:70: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/concrete/tests/test_sums_products.py:1596:69: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/concrete/tests/test_sums_products.py:1597:69: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/concrete/tests/test_sums_products.py:1598:82: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/concrete/tests/test_sums_products.py:1599:79: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/add.py:269:25: error[missing-argument] No argument provided for required parameter 2
- sympy/core/add.py:321:17: error[unsupported-operator] Operator `+=` is unsupported between objects of type `Number` and `Number`
- sympy/core/benchmarks/bench_numbers.py:88:5: error[unsupported-operator] Operator `+` is unsupported between objects of type `Rational` and `Literal[1]`
- sympy/core/benchmarks/bench_numbers.py:92:5: error[unsupported-operator] Operator `+` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/evalf.py:1224:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `int | NegativeInfinity` and `int | NegativeInfinity`
- sympy/core/evalf.py:1278:13: error[unsupported-operator] Operator `*=` is unsupported between objects of type `Rational` and `int | Unknown`
- sympy/core/expr.py:2625:30: error[unsupported-operator] Operator `/` is unsupported between objects of type `Zero | Unknown` and `Literal[2]`
- sympy/core/expr.py:4091:34: error[unsupported-operator] Operator `/` is unsupported between objects of type `Float` and `int | float`
- sympy/core/mul.py:1920:25: error[unsupported-operator] Operator `-=` is unsupported between objects of type `Infinity & ~AlwaysFalsy` and `(Unknown & ~AlwaysFalsy) | Literal[1]`
- sympy/core/numbers.py:378:24: error[unsupported-operator] Operator `*` is unsupported between objects of type `Number & ~AlwaysFalsy` and `int`
- sympy/core/random.py:127:10: error[missing-argument] No argument provided for required parameter 2
- sympy/core/tests/test_args.py:5425:23: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[2]` and `DyadicAdd`
- sympy/core/tests/test_arit.py:119:29: error[unsupported-operator] Operator `/` is unsupported between objects of type `Rational` and `Literal[2]`
- sympy/core/tests/test_arit.py:149:19: error[unsupported-operator] Operator `/` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_arit.py:153:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_arit.py:213:51: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_arit.py:213:62: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[6]`
- sympy/core/tests/test_arit.py:213:70: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[32]`
- sympy/core/tests/test_arit.py:1856:14: error[unsupported-operator] Operator `%` is unsupported between objects of type `Float` and `Literal[1]`
- sympy/core/tests/test_arit.py:1918:17: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[10]`
- sympy/core/tests/test_arit.py:1918:42: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[10]`
- sympy/core/tests/test_arit.py:2218:16: error[unsupported-operator] Operator `+` is unsupported between objects of type `Literal[1]` and `Rational`
- sympy/core/tests/test_arit.py:2487:24: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/core/tests/test_arit.py:2487:46: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_assumptions.py:1030:33: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[0]` and `Infinity`
- sympy/core/tests/test_assumptions.py:1031:8: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[0]` and `Infinity`
- sympy/core/tests/test_complex.py:148:10: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_complex.py:150:10: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_complex.py:151:26: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[1024]`
- sympy/core/tests/test_complex.py:205:28: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_count_ops.py:57:18: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[3]`
- sympy/core/tests/test_count_ops.py:81:22: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_eval.py:21:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_evalf.py:273:19: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `int`
- sympy/core/tests/test_expand.py:150:36: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_expr.py:441:35: error[unsupported-operator] Operator `+` is unsupported between objects of type `Unknown | Rational | Float | Symbol` and `Literal["1"]`
- sympy/core/tests/test_expr.py:442:35: error[unsupported-operator] Operator `-` is unsupported between objects of type `Unknown | Rational | Float | Symbol` and `Literal["1"]`
- sympy/core/tests/test_expr.py:444:20: error[unsupported-operator] Operator `*` is unsupported between objects of type `Unknown | Rational | Float | Symbol` and `Literal["1"]`
- sympy/core/tests/test_expr.py:446:39: error[unsupported-operator] Operator `*` is unsupported between objects of type `(Unknown & ~Literal[2]) | Rational | Float | Symbol` and `Literal["1"]`
- sympy/core/tests/test_expr.py:447:35: error[unsupported-operator] Operator `/` is unsupported between objects of type `Unknown | Rational | Float | Symbol` and `Literal["1"]`
- sympy/core/tests/test_expr.py:669:25: error[unsupported-operator] Operator `/` is unsupported between objects of type `NaN | Infinity | NegativeInfinity | ComplexInfinity` and `Literal[1] | Symbol`
- sympy/core/tests/test_expr.py:705:36: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:709:27: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[3]`
- sympy/core/tests/test_expr.py:710:27: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[3]`
- sympy/core/tests/test_expr.py:711:27: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[3]`
- sympy/core/tests/test_expr.py:725:9: error[unsupported-operator] Operator `*` is unsupported between objects of type `Rational` and `MyInt`
- sympy/core/tests/test_expr.py:728:31: error[unsupported-operator] Operator `*` is unsupported between objects of type `Rational` and `<class 'MyInt'>`
- sympy/core/tests/test_expr.py:736:9: error[unsupported-operator] Operator `*` is unsupported between objects of type `Rational` and `MyInt`
- sympy/core/tests/test_expr.py:739:31: error[unsupported-operator] Operator `*` is unsupported between objects of type `Rational` and `<class 'MyInt'>`
- sympy/core/tests/test_expr.py:1446:38: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[8]`
- sympy/core/tests/test_expr.py:1878:10: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[14]`
- sympy/core/tests/test_expr.py:1881:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1883:10: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[21]`
- sympy/core/tests/test_expr.py:1940:18: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/core/tests/test_expr.py:1940:30: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[4]`
- sympy/core/tests/test_expr.py:1940:48: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[4]`
- sympy/core/tests/test_expr.py:1947:23: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_expr.py:1947:47: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_expr.py:1948:23: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_expr.py:1948:47: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_expr.py:1952:25: error[unsupported-operator] Operator `/` is unsupported between objects of type `Rational` and `Literal[2]`
- sympy/core/tests/test_expr.py:1970:29: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1970:47: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1970:64: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1971:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[12]`
- sympy/core/tests/test_expr.py:1971:31: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/core/tests/test_expr.py:1971:54: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1972:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1972:22: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1972:33: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[12]`
- sympy/core/tests/test_expr.py:1972:54: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1973:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1973:22: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1973:33: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[6]`
- sympy/core/tests/test_expr.py:1973:46: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[4]`
- sympy/core/tests/test_expr.py:1974:7: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1974:25: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1974:42: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1974:53: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[12]`
- sympy/core/tests/test_expr.py:1975:7: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/core/tests/test_expr.py:1975:30: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1975:48: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1975:65: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1976:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[12]`
- sympy/core/tests/test_expr.py:1976:26: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1976:44: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1976:61: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1977:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[6]`
- sympy/core/tests/test_expr.py:1977:18: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[4]`
- sympy/core/tests/test_expr.py:1977:49: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1978:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1978:22: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1978:33: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[12]`
- sympy/core/tests/test_expr.py:1979:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/core/tests/test_expr.py:1979:28: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1979:46: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1979:63: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1980:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[12]`
- sympy/core/tests/test_expr.py:1980:26: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1980:44: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1980:61: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1981:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[6]`
- sympy/core/tests/test_expr.py:1981:18: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[4]`
- sympy/core/tests/test_expr.py:1981:51: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1982:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1982:22: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1982:33: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[12]`
- sympy/core/tests/test_expr.py:1983:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[4]`
- sympy/core/tests/test_expr.py:1983:28: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1983:46: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1983:63: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1984:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[12]`
- sympy/core/tests/test_expr.py:1984:26: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[8]`
- sympy/core/tests/test_expr.py:1984:44: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[13824]`
- sympy/core/tests/test_expr.py:1984:61: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_expr.py:1985:5: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[6]`
- sympy/core/tests/test_expr.py:1985:18: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[4]`
- sympy/core/tests/test_expr.py:2142:20: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[1]` and `Integer`
- sympy/core/tests/test_expr.py:2208:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Float` and `Literal[1]`
- sympy/core/tests/test_exprtools.py:73:46: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_exprtools.py:73:70: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_exprtools.py:74:24: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_exprtools.py:74:50: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_exprtools.py:165:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[4]`
- sympy/core/tests/test_exprtools.py:177:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[64]`
- sympy/core/tests/test_exprtools.py:179:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[8]`
- sympy/core/tests/test_exprtools.py:284:50: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_exprtools.py:284:71: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_function.py:563:83: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_function.py:564:87: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[2]`
- sympy/core/tests/test_function.py:628:16: error[missing-argument] No argument provided for required parameter 2
- sympy/core/tests/test_function.py:921:36: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_function.py:922:65: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_function.py:1075:14: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[12]`
- sympy/core/tests/test_function.py:1097:45: error[unsupported-operator] Operator `/` is unsupported between objects of type `Integer` and `Literal[24]`
- sympy/core/tests/test_function.py:1099:26: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[24]`
- sympy/core/tests/test_function.py:1133:18: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[8]`
- sympy/core/tests/test_match.py:32:20: error[unsupported-operator] Operator `+` is unsupported between objects of type `Rational` and `Literal[1]`
- sympy/core/tests/test_match.py:396:34: error[unsupported-operator] Operator `/` is unsupported between objects of type `Rational` and `Literal[3]`
- sympy/core/tests/test_match.py:600:36: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_match.py:605:36: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[3]`
- sympy/core/tests/test_match.py:631:32: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[1]` and `Integer`
- sympy/core/tests/test_match.py:657:13: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[8]`
- sympy/core/tests/test_match.py:658:24: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[8]`
- sympy/core/tests/test_numbers.py:54:32: error[unsupported-operator] Operator `/` is unsupported between objects of type `Zero` and `Zero`
- sympy/core/tests/test_numbers.py:56:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Zero` and `Zero`
- sympy/core/tests/test_numbers.py:64:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Half` and `Half`
- sympy/core/tests/test_numbers.py:65:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Half` and `Rational`
- sympy/core/tests/test_numbers.py:66:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Half` and `Rational`
- sympy/core/tests/test_numbers.py:67:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Half`
- sympy/core/tests/test_numbers.py:68:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_numbers.py:69:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_numbers.py:70:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Half`
- sympy/core/tests/test_numbers.py:71:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_numbers.py:72:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_numbers.py:76:13: error[unsupported-operator] Operator `%` is unsupported between objects of type `Float` and `float`
- sympy/core/tests/test_numbers.py:77:13: error[unsupported-operator] Operator `%` is unsupported between objects of type `Float` and `Literal[2]`
- sympy/core/tests/test_numbers.py:78:13: error[unsupported-operator] Operator `%` is unsupported between objects of type `Float` and `float`
- sympy/core/tests/test_numbers.py:82:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Infinity` and `Infinity`
- sympy/core/tests/test_numbers.py:84:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Literal[5]` and `Infinity`
- sympy/core/tests/test_numbers.py:93:9: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Float`
- sympy/core/tests/test_numbers.py:94:17: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_numbers.py:97:9: error[unsupported-operator] Operator `%` is unsupported between objects of type `Float` and `Rational`
- sympy/core/tests/test_numbers.py:98:17: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_numbers.py:107:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Rational` and `Float`
- sympy/core/tests/test_numbers.py:108:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Float` and `Rational`
- sympy/core/tests/test_numbers.py:109:12: error[missing-argument] No argument provided for required parameter 2
- sympy/core/tests/test_numbers.py:110:12: error[missing-argument] No argument provided for required parameter 2
- sympy/core/tests/test_numbers.py:111:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `float` and `Float`
- sympy/core/tests/test_numbers.py:442:13: error[unsupported-operator] Operator `+` is unsupported between objects of type `Rational` and `Literal[1]`
- sympy/core/tests/test_numbers.py:443:14: error[unsupported-operator] Operator `+` is unsupported between objects of type `Rational` and `Rational`
- sympy/core/tests/test_numbers.py:620:15: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[10]`
- sympy/core/tests/test_numbers.py:621:15: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[10]`
- sympy/core/tests/test_numbers.py:622:15: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[10]`
- sympy/core/tests/test_numbers.py:623:15: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[10]`
- sympy/core/tests/test_numbers.py:687:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `Float` and `Float`
- sympy/core/tests/test_numbers.py:692:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `Float` and `Float`
- sympy/core/tests/test_numbers.py:715:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[1]` and `Infinity`
- sympy/core/tests/test_numbers.py:719:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Infinity` and `Literal[1]`
- sympy/core/tests/test_numbers.py:720:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Literal[2]` and `Infinity`
- sympy/core/tests/test_numbers.py:721:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[3]` and `Infinity`
- sympy/core/tests/test_numbers.py:725:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Infinity` and `Infinity`
- sympy/core/tests/test_numbers.py:726:18: error[unsupported-operator] Operator `*` is unsupported between objects of type `Infinity` and `Literal[-5]`
- sympy/core/tests/test_numbers.py:730:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Infinity` and `Literal[2]`
- sympy/core/tests/test_numbers.py:731:12: error[unsupported-operator] Operator `%` is unsupported between objects of type `Literal[2]` and `Infinity`
- sympy/core/tests/test_numbers.py:732:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Infinity` and `Infinity`
- sympy/core/tests/test_numbers.py:736:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `Infinity` and `Infinity`
- sympy/core/tests/test_numbers.py:742:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Infinity` and `Infinity`
- sympy/core/tests/test_numbers.py:746:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Infinity` and `Infinity`
- sympy/core/tests/test_numbers.py:750:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Infinity` and `Literal[0]`
- sympy/core/tests/test_numbers.py:754:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Infinity` and `Literal[0]`
- sympy/core/tests/test_numbers.py:756:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[0]` and `Infinity`
- sympy/core/tests/test_numbers.py:758:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Infinity` and `Literal[0]`
- sympy/core/tests/test_numbers.py:760:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Literal[0]` and `Infinity`
- sympy/core/tests/test_numbers.py:762:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `Infinity` and `Literal[0]`
- sympy/core/tests/test_numbers.py:764:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `Literal[0]` and `Infinity`
- sympy/core/tests/test_numbers.py:766:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Infinity` and `Literal[2]`
- sympy/core/tests/test_numbers.py:768:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Infinity` and `Literal[-2]`
- sympy/core/tests/test_numbers.py:770:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Infinity` and `Literal[2]`
- sympy/core/tests/test_numbers.py:772:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Infinity` and `Literal[-2]`
- sympy/core/tests/test_numbers.py:777:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[2]` and `Infinity`
- sympy/core/tests/test_numbers.py:779:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Literal[-2]` and `Infinity`
- sympy/core/tests/test_numbers.py:781:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Literal[2]` and `Infinity`
- sympy/core/tests/test_numbers.py:782:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `Literal[2]` and `Infinity`
- sympy/core/tests/test_numbers.py:783:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Literal[-2]` and `Infinity`
- sympy/core/tests/test_numbers.py:784:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `Literal[-2]` and `Infinity`
- sympy/core/tests/test_numbers.py:793:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:793:37: error[unsupported-operator] Operator `*` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:795:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:795:37: error[unsupported-operator] Operator `/` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:797:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:797:39: error[unsupported-operator] Operator `*` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:799:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:799:39: error[unsupported-operator] Operator `/` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:801:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:801:39: error[unsupported-operator] Operator `+` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:803:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:803:39: error[unsupported-operator] Operator `-` is unsupported between objects of type `Infinity` and `float`
- sympy/core/tests/test_numbers.py:805:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `float` and `Infinity`
- sympy/core/tests/test_numbers.py:805:37: error[unsupported-operator] Operator `*` is unsupported between objects of type `float` and `Infinity`
- sympy/core/tests/test_numbers.py:809:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `float` and `Infinity`
- sympy/core/tests/test_numbers.py:809:39: error[unsupported-operator] Operator `*` is unsupported between objects of type `float` and `Infinity`
- sympy/core/tests/test_numbers.py:813:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `float` and `Infinity`
- sympy/core/tests/test_numbers.py:815:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `float` and `Infinity`
- sympy/core/tests/test_numbers.py:825:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `NaN` and `float`
- sympy/core/tests/test_numbers.py:827:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `NaN` and `Infinity`
- sympy/core/tests/test_numbers.py:831:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `NaN` and `Infinity`
- sympy/core/tests/test_numbers.py:833:12: error[unsupported-operator] Operator `-` is unsupported between objects of type `NaN` and `Infinity`
- sympy/core/tests/test_numbers.py:862:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `NaN` and `One`
- sympy/core/tests/test_numbers.py:898:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Float` and `float`
- sympy/core/tests/test_numbers.py:899:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Float` and `float`
- sympy/core/tests/test_numbers.py:900:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Float` and `float`
- sympy/core/tests/test_numbers.py:901:12: error[unsupported-operator] Operator `*` is unsupported between objects of type `Float` and `float`
- sympy/core/tests/test_numbers.py:909:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[1]` and `Zero`
- sympy/core/tests/test_numbers.py:911:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[0]` and `Zero`
- sympy/core/tests/test_numbers.py:913:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Zero` and `Literal[0]`
- sympy/core/tests/test_numbers.py:914:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Float` and `Literal[0]`
- sympy/core/tests/test_numbers.py:915:12: error[unsupported-operator] Operator `/` is unsupported between objects of type `Literal[-1]` and `Zero`
- sympy/core/tests/test_numbers.py:983:12: error[unsupported-operator] Operator `+` is unsupported between objects of type `NaN` and `NaN`
- sympy/core/tests/test_numbers.py:984:19: error[unsupported-operator] Operator `*` is unsupported between objects of type `NaN` and `Literal[-5]`
- sympy/core/tests/test_numbers.py:1108:18: error[unsupported-operator] Operator `+` is unsupported between objects of type `Literal[4503599761588223]` and `Half`
- sympy/core/tests/test_numbers.py:1109:18: error[unsupported-operator] Operator `+` is unsupported between objects of type `Literal[4503599761588224]` and `Half`
- sympy/core/tests/test_numbers.py:1110:18: error[unsupported-operator] Operator `+` is unsupported between objects of type `Literal[4503599761588225]` and `Half`
- sympy/core/tests/test_numbers.py:1123:18: error[unsupported-operator] Operator `-` is unsupported between objects of type `Literal[1]` and `Rational`
- sympy/core/tests/test_numbers.py:1124:18: error[unsupported-operator] Operator `-` is unsupported between objects of type `Literal[4503599761588224]` and `Rational`
- sympy/core/tests/test_numbers.py:1125:18: error[unsupported-operator] Operator `-` is unsupported between objects of type `int` and `Rational`
- sympy/core/tests/test_numbers.py:1142:56: error[unsupported-operator] Operator `/` is unsupported between objects of type `One` and `Literal[5]`
- sympy/core/tests/test_numbers.py:1500:17: error[unsupported-...*[Comment body truncated]*

@sharkdp sharkdp changed the title [ty] Treat Callables as bound-method descripors in special cases [ty] Treat Callables as bound-method descriptors in special cases Oct 10, 2025
Copy link
Contributor

github-actions bot commented Oct 10, 2025

ecosystem-analyzer results

Lint rule Added Removed Changed
unsupported-operator 0 2,961 0
missing-argument 0 37 0
unresolved-attribute 0 3 0
possibly-missing-attribute 0 2 0
unused-ignore-comment 2 0 0
invalid-assignment 1 0 0
no-matching-overload 0 1 0
Total 3 3,004 0

Full report with detailed diff (timing results)

python-version = "3.14"
```

## Introduction
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines +166 to +190
The reason for this is that the heuristic is problematic. We don't *know* that the `Callable` in the
return type of `memoize` is actually related to the method that we pass in. But when `memoize` is
applied as a decorator, it is reasonable to assume so.

In general, a function call might however return a `Callable` that is unrelated to the argument
passed in. And here, it seems more reasonable and safe to treat the `Callable` as a non-descriptor.
This allows correct programs like the following to pass type checking (that are currently rejected
by pyright and mypy with a heuristic that apparently applies in a wider range of situations):

```py
class SquareCalculator:
def __init__(self, post_process: Callable[[float], int]):
self.post_process = post_process

def __call__(self, x: float) -> int:
return self.post_process(x * x)

def square_then(c: Callable[[float], int]) -> Callable[[float], int]:
return SquareCalculator(c)

class Calculator:
square_then_round = square_then(round)

reveal_type(Calculator().square_then_round(3.14)) # revealed: Unknown | int
```
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The argument here is a bit weak. I had trouble coming up with a better example.

It still feels wrong to me to generally assume that returned Callable types are function-like if a function-like callable is passed into a call (would we try to detect that in every possible parameter position? or only apply the heuristic for single-argument calls?).

Copy link
Member

Choose a reason for hiding this comment

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

The most common example where a non-function callable is returned by a decorator is functools._lru_cache_wrapper:

% py
Python 3.13.1 (main, Jan  3 2025, 12:04:03) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import functools
>>> class F:
...     @functools.lru_cache
...     def whatever(self): ...
...     
>>> F.whatever
<functools._lru_cache_wrapper object at 0x101549640>

But (somewhat famously), _lru_cache_wrapper has the same descriptor-binding behaviour that types.FunctionType has. So you could use that as an argument in favour of assuming that all objects returned from decorators have this method-binding behaviour if they have __call__ attributes, I suppose...

@sharkdp sharkdp marked this pull request as ready for review October 13, 2025 13:49
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Nearly all the ecosystem diff appears to be due to the bind_self fix in signatures.rs, which actually seems unrelated to the rest of the PR... I wonder if we could separate that out into a standalone PR, so that we can see the impact of the special case here more clearly?

Comment on lines +23 to +28
def _(
accessed_on_class: CallableTypeOf[C1.method],
accessed_on_instance: CallableTypeOf[C1().method],
):
reveal_type(accessed_on_class) # revealed: (self: C1, x: int) -> str
reveal_type(accessed_on_instance) # revealed: (x: int) -> str
Copy link
Member

@AlexWaygood AlexWaygood Oct 13, 2025

Choose a reason for hiding this comment

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

off-topic: a reveal_typeform function would be pretty useful for this kind of mdtest (and for playing around in the playground). Rather than having to create the function, I could just do reveal_typeform(CallableTypeOf[C1.method]) and it would print the signature in a diagnostic

Copy link
Contributor Author

Choose a reason for hiding this comment

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

a reveal_typeform function would be pretty useful

Yes!!

Copy link
Contributor Author

@sharkdp sharkdp Oct 13, 2025

Choose a reason for hiding this comment

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

Or if Python had explicitly specialized calls to generic functions, we could finally add C++'s std::declval:

def declval[T]() -> T:
    raise RuntimeError("can not make up a `T` out of thin air")

reveal_type(declval[CallableTypeOf[C1.method]]())

Beautiful!

Comment on lines +31 to +33
Other callable objects (`staticmethod` objects, instances of classes with a `__call__` method but no
dedicated `__get__` method) are *not* bound-method descriptors. If accessed as class attributes via
an instance, they are simply themselves:
Copy link
Member

Choose a reason for hiding this comment

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

staticmethod does actually have a __get__ method at runtime -- it returns the underlying function object (whether it's accessed on the class or the instance). On Python <=3.9, staticmethods are not directly callable; it's only by calling __get__ on the staticmethod that you retrieve the original function object and get something that you can actually call:

% uvx python3.9                             
Python 3.9.6 (default, Apr 30 2025, 02:07:17) 
[Clang 17.0.0 (clang-1700.0.13.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
...     @staticmethod
...     def bar(): return 42
... 
>>> original_staticmethod = Foo.__dict__['bar']
>>> original_staticmethod
<staticmethod object at 0x100575370>
>>> original_staticmethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable
>>> Foo.bar
<function Foo.bar at 0x1005fb4c0>
>>> Foo.bar()
42

On Python 3.10, staticmethod.__call__ was added, so staticmethod objects are now directly callable. But it's still the case that staticmethods are descriptors that return the underlying function object when you access them, on either the class object or an instance of the class.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

staticmethod does actually have a __get__ method at runtime -- it returns the underlying function object

Right, I know. The text says "Other callable objects (staticmethod objects, […]) are not bound-method descriptors", where "bound-method descriptor" would imply the sort of self-binding behavior that we know from normal functions. But the text could certainly be clarified further, if you think that'd be valuable.

On Python 3.10, staticmethod.__call__ was added, so staticmethod objects are now directly callable.

TIL!

Copy link
Member

Choose a reason for hiding this comment

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

The text says "Other callable objects (staticmethod objects, […]) are not bound-method descriptors"

Hmmmm, but it also says:

If accessed as class attributes via
an instance, they are simply themselves

Which I don't think is accurate for staticmethods — they are descriptors, just not in the same way as instance methods

Comment on lines +166 to +190
The reason for this is that the heuristic is problematic. We don't *know* that the `Callable` in the
return type of `memoize` is actually related to the method that we pass in. But when `memoize` is
applied as a decorator, it is reasonable to assume so.

In general, a function call might however return a `Callable` that is unrelated to the argument
passed in. And here, it seems more reasonable and safe to treat the `Callable` as a non-descriptor.
This allows correct programs like the following to pass type checking (that are currently rejected
by pyright and mypy with a heuristic that apparently applies in a wider range of situations):

```py
class SquareCalculator:
def __init__(self, post_process: Callable[[float], int]):
self.post_process = post_process

def __call__(self, x: float) -> int:
return self.post_process(x * x)

def square_then(c: Callable[[float], int]) -> Callable[[float], int]:
return SquareCalculator(c)

class Calculator:
square_then_round = square_then(round)

reveal_type(Calculator().square_then_round(3.14)) # revealed: Unknown | int
```
Copy link
Member

Choose a reason for hiding this comment

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

The most common example where a non-function callable is returned by a decorator is functools._lru_cache_wrapper:

% py
Python 3.13.1 (main, Jan  3 2025, 12:04:03) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import functools
>>> class F:
...     @functools.lru_cache
...     def whatever(self): ...
...     
>>> F.whatever
<functools._lru_cache_wrapper object at 0x101549640>

But (somewhat famously), _lru_cache_wrapper has the same descriptor-binding behaviour that types.FunctionType has. So you could use that as an argument in favour of assuming that all objects returned from decorators have this method-binding behaviour if they have __call__ attributes, I suppose...

Ok(return_ty) => {
let is_input_function_like = inferred_ty
.into_callable(self.db())
.and_then(Type::unwrap_as_callable_type)
Copy link
Member

@AlexWaygood AlexWaygood Oct 13, 2025

Choose a reason for hiding this comment

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

Note that unwrap_as_callable_type will return None if into_callable returns Some(Type::Union), even if each element of the union returned was a Callable type

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, that's a good catch! Will look into this tomorrow (post-merge, I don't think it's critical).

@sharkdp sharkdp merged commit 4b8e278 into main Oct 13, 2025
51 of 52 checks passed
@sharkdp sharkdp deleted the david/callables-as-descriptors branch October 13, 2025 19:17
dcreager added a commit that referenced this pull request Oct 13, 2025
…tity

* origin/main: (24 commits)
  Update Python compatibility from 3.13 to 3.14 in README.md (#20852)
  [syntax-errors]: break outside loop F701 (#20556)
  [ty] Treat `Callable`s as bound-method descriptors in special cases (#20802)
  [ty] Do not bind self to non-positional parameters (#20850)
  Fix syntax error false positives on parenthesized context managers (#20846)
  [ty] Remove 'pre-release software' warning (#20817)
  Render unsupported syntax errors in formatter tests (#20777)
  [ty] Treat functions, methods, and dynamic types as function-like `Callable`s (#20842)
  [ty] Move logic for `super()` inference to a new `types::bound_super` submodule (#20840)
  [ty] Fix false-positive diagnostics on `super()` calls (#20814)
  [ty] Move `class_member` to `member` module (#20837)
  [`ruff`] Use DiagnosticTag for more flake8 and numpy rules (#20758)
  [ty] Prefer declared base class attribute over inferred attribute on subclass (#20764)
  [ty] Log files that are slow to type check (#20836)
  Update cargo-bins/cargo-binstall action to v1.15.7 (#20827)
  Update CodSpeedHQ/action action to v4.1.1 (#20828)
  Update Rust crate pyproject-toml to v0.13.7 (#20835)
  Update Rust crate anstream to v0.6.21 (#20829)
  Update Rust crate libc to v0.2.177 (#20832)
  Update Rust crate memchr to v2.7.6 (#20834)
  ...
dcreager added a commit that referenced this pull request Oct 13, 2025
* main: (25 commits)
  [ty] Diagnostic for generic classes that reference typevars in enclosing scope (#20822)
  Update Python compatibility from 3.13 to 3.14 in README.md (#20852)
  [syntax-errors]: break outside loop F701 (#20556)
  [ty] Treat `Callable`s as bound-method descriptors in special cases (#20802)
  [ty] Do not bind self to non-positional parameters (#20850)
  Fix syntax error false positives on parenthesized context managers (#20846)
  [ty] Remove 'pre-release software' warning (#20817)
  Render unsupported syntax errors in formatter tests (#20777)
  [ty] Treat functions, methods, and dynamic types as function-like `Callable`s (#20842)
  [ty] Move logic for `super()` inference to a new `types::bound_super` submodule (#20840)
  [ty] Fix false-positive diagnostics on `super()` calls (#20814)
  [ty] Move `class_member` to `member` module (#20837)
  [`ruff`] Use DiagnosticTag for more flake8 and numpy rules (#20758)
  [ty] Prefer declared base class attribute over inferred attribute on subclass (#20764)
  [ty] Log files that are slow to type check (#20836)
  Update cargo-bins/cargo-binstall action to v1.15.7 (#20827)
  Update CodSpeedHQ/action action to v4.1.1 (#20828)
  Update Rust crate pyproject-toml to v0.13.7 (#20835)
  Update Rust crate anstream to v0.6.21 (#20829)
  Update Rust crate libc to v0.2.177 (#20832)
  ...
dcreager added a commit that referenced this pull request Oct 14, 2025
…rable

* origin/main: (26 commits)
  [ty] Add separate type for typevar "identity" (#20813)
  [ty] Diagnostic for generic classes that reference typevars in enclosing scope (#20822)
  Update Python compatibility from 3.13 to 3.14 in README.md (#20852)
  [syntax-errors]: break outside loop F701 (#20556)
  [ty] Treat `Callable`s as bound-method descriptors in special cases (#20802)
  [ty] Do not bind self to non-positional parameters (#20850)
  Fix syntax error false positives on parenthesized context managers (#20846)
  [ty] Remove 'pre-release software' warning (#20817)
  Render unsupported syntax errors in formatter tests (#20777)
  [ty] Treat functions, methods, and dynamic types as function-like `Callable`s (#20842)
  [ty] Move logic for `super()` inference to a new `types::bound_super` submodule (#20840)
  [ty] Fix false-positive diagnostics on `super()` calls (#20814)
  [ty] Move `class_member` to `member` module (#20837)
  [`ruff`] Use DiagnosticTag for more flake8 and numpy rules (#20758)
  [ty] Prefer declared base class attribute over inferred attribute on subclass (#20764)
  [ty] Log files that are slow to type check (#20836)
  Update cargo-bins/cargo-binstall action to v1.15.7 (#20827)
  Update CodSpeedHQ/action action to v4.1.1 (#20828)
  Update Rust crate pyproject-toml to v0.13.7 (#20835)
  Update Rust crate anstream to v0.6.21 (#20829)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ecosystem-analyzer ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bind_self mistakenly binds non-positional parameters

2 participants