typeshed
typeshed copied to clipboard
Add `__call__` attribute to `function`
I guess the lack of this attribute causes mypy and pyright to emit a false positive error for the following code.
def a(): pass
a.__call__
mypy:
file.py:2: error: "Callable[[], Any]" not callable [operator]
pyright:
file.py
file.py:2:3 - error: Cannot access attribute "__call__" for class "function"
Attribute "__call__" is unknown (reportFunctionMemberAccess)
Diff from mypy_primer, showing the effect of this PR on open source code:
discord.py (https://github.com/Rapptz/discord.py)
- discord/backoff.py:75: error: Incompatible types in assignment (expression has type "function", variable has type "Callable[..., int | float]") [assignment]
schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/service/extensions.py:182: error: Unused "type: ignore" comment [unused-ignore]
+ src/schemathesis/specs/openapi/_hypothesis.py: note: At top level:
+ src/schemathesis/specs/openapi/_hypothesis.py:422: error: Unused "type: ignore" comment [unused-ignore]
+ src/schemathesis/cli/__init__.py: note: At top level:
+ src/schemathesis/cli/__init__.py:1472: error: Unused "type: ignore" comment [unused-ignore]
+ src/schemathesis/cli/__init__.py:1477: error: Unused "type: ignore" comment [unused-ignore]
+ src/schemathesis/cli/__init__.py:1478: error: Unused "type: ignore" comment [unused-ignore]
pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/computation/ops.py:523: error: Unused "type: ignore" comment [unused-ignore]
ignite (https://github.com/pytorch/ignite)
+ ignite/metrics/fbeta.py:154: error: Unused "type: ignore" comment [unused-ignore]
+ ignite/metrics/fbeta.py:163: error: Unused "type: ignore" comment [unused-ignore]
sphinx (https://github.com/sphinx-doc/sphinx)
+ sphinx/directives/__init__.py:327: error: Unused "type: ignore" comment [unused-ignore]
+ sphinx/util/rst.py: note: At top level:
+ sphinx/util/rst.py:69: error: Unused "type: ignore" comment [unused-ignore]
pandera (https://github.com/pandera-dev/pandera)
+ tests/strategies/test_strategies.py:1010: error: Unused "type: ignore" comment [unused-ignore]
+ tests/core/test_decorators.py:429: error: Unused "type: ignore" comment [unused-ignore]
+ tests/core/test_decorators.py:442: error: Unused "type: ignore" comment [unused-ignore]
trio (https://github.com/python-trio/trio)
+ src/trio/_core/_ki.py:199: error: Unused "type: ignore" comment [unused-ignore]
+ src/trio/_core/_ki.py:202: error: Unused "type: ignore" comment [unused-ignore]
dd-trace-py (https://github.com/DataDog/dd-trace-py)
+ ddtrace/_trace/utils_redis.py:34: error: Unused "type: ignore" comment [unused-ignore]
scrapy (https://github.com/scrapy/scrapy)
+ scrapy/extensions/httpcache.py:324: error: Unused "type: ignore" comment [unused-ignore]
werkzeug (https://github.com/pallets/werkzeug)
- tests/test_formparser.py:436: error: Argument "stream_factory" to "MultiPartParser" has incompatible type "Callable[[], Any]"; expected "TStreamFactory | None" [arg-type]
- tests/test_formparser.py:438: error: Non-overlapping identity check (left operand type: "TStreamFactory", right operand type: "Callable[[], Any]") [comparison-overlap]
jax (https://github.com/google/jax)
+ jax/_src/core.py:3227: error: Unused "type: ignore" comment [unused-ignore]
+ jax/_src/pallas/mosaic/random.py:158: error: Unused "type: ignore" comment [unused-ignore]
+ jax/_src/pallas/mosaic/random.py:159: error: Unused "type: ignore" comment [unused-ignore]
+ jax/_src/pallas/mosaic/random.py:160: error: Unused "type: ignore" comment [unused-ignore]
+ jax/experimental/jax2tf/tests/shape_poly_test.py:2219: error: Unused "type: ignore" comment [unused-ignore]
graphql-core (https://github.com/graphql-python/graphql-core)
+ src/graphql/execution/execute.py:554: error: Unused "type: ignore" comment [unused-ignore]
+ tests/execution/test_abstract.py:44: error: Unused "type: ignore" comment [unused-ignore]
black (https://github.com/psf/black)
- src/blackd/__init__.py:91:22: error: List item 0 has incompatible type "Callable[[Request, Callable[[Request], Awaitable[StreamResponse]]], Awaitable[StreamResponse]]"; expected "Middleware" [list-item]
starlette (https://github.com/encode/starlette)
+ tests/test_applications.py:128: error: Unused "type: ignore" comment [unused-ignore]
dragonchain (https://github.com/dragonchain/dragonchain)
- dragonchain/job_processor/contract_job.py:307:24: error: Cannot call function of unknown type [operator]
- dragonchain/job_processor/contract_job.py:344:20: error: Cannot call function of unknown type [operator]
prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/cli/profile.py:177: error: Cannot call function of unknown type [operator]
antidote (https://github.com/Finistere/antidote)
+ tests/lib/interface/test_custom.py:434: error: Unused "type: ignore" comment [unused-ignore]
+ tests/lib/interface/test_custom.py:437: error: Unused "type: ignore" comment [unused-ignore]
+ tests/lib/interface/test_custom.py:440: error: Unused "type: ignore" comment [unused-ignore]
+ tests/lib/interface/test_custom.py:443: error: Unused "type: ignore" comment [unused-ignore]
+ tests/lib/interface/test_custom.py:446: error: Unused "type: ignore" comment [unused-ignore]
+ tests/lib/interface/test_custom.py:449: error: Unused "type: ignore" comment [unused-ignore]
This looks completely reasonable to me, suspiciously so, in fact. And the primer hits seem to agree, although I haven't looked at the "red" hits in detail. I wonder whether there was any reason we didn't do this earlier? Maybe it's related to the fact that this is a "fake" type that seems to mainly exist for the benefit of mypy? Still, at first glance this looks like a sensible change.
I'm not sure this is right. I suspect it simply makes mypy accept a lot more code because functions now get signature (*Any, **Any) -> Any more easily.
Yeah... if you look at e.g. https://github.com/pandas-dev/pandas/blob/59bb3f44a9bdd6d79704caab4d5c4e229945aefd/pandas/core/computation/ops.py#L522-L523 (one of the errors going away here), it's clear that mypy already knows that it has an object of type function there, and it's clear that it knows that the function object is in fact callable. So ISTM that it's very much a deliberate choice on the part of mypy to emit an error there (because it doesn't know the signature of the function being called); but if we make this change, it will no longer be able to emit that error, because it'll find the (*Any, **Any) -> Any signature in the stub before it's able to fallback to the hook it has for builtins.function and emit the proper error message
builtins.function is a legacy thing that mypy needs for historical reasons, see https://github.com/python/mypy/issues/8240. Usually it uses Callable or some other class with a __call__. My guess is that the "Cannot call function of unknown type" made sense at the time it was implemented, but IMO it doesn't fit our "prefer false negatives" philosophy. If we can somehow make builtins.function less painful to users, why not?
The pyright error does not make sense to me. Perhaps "function" in the pyright error refers to something else than builtins.function.
Closing as I don't think this makes mypy more useful. In the long term we should get rid of builtins.function from the stub (and I would recommend all type checkers to move away from relying on it).
Closing as I don't think this makes mypy more useful. In the long term we should get rid of
builtins.functionfrom the stub (and I would recommend all type checkers to move away from relying on it).
Maybe we should just remove it? As far as I understand, at least mypy patches typeshed anyway, and this could be another incentive to remove reliance on this type.
That feels a bit rude to do unilaterally, I'd rather see this fixed in mypy first. (And I'm not sure if other type checkers also rely on builtins.function.)