Amending 3rd party library type annotations

Hello. I’m using sympy library where many annotations are missing and some of the existing ones are just wrong.
Is it possible to override them on case by case basis? I’ll give an example:

There’s this type called Basic. I need to persuade mypy that it implements SupportsFloat protocol and I need to completely replace type annotations on its subs method while keeping everything else as-is.

I’ve always added stubs as .pyi files somewhere, then used

import typing

if typing.TYPE_CHECKING:
    from stub import attr
else:
    from module import attr

Although this adds a minor overhead with importing typing of course.

This has a problem that during type check your stub attr does not match attr returned or taken by methods in the library. E.g.:

self._size: Basic = sp.sympify(size)

mypy gives assignment error because type of _size is the new stub but sympify returns the true Basic.

One option that would be good for both yourself and future users of sympy would be to open a pull request that fixes any incorrect type annotations that you have seen.

The Basic class does not have the __float__ method so it is not a subtype of SupportsFloat. Instead the problem is presumably that what you have is something of type Expr (a subclass of Basic) that is of type SupportsFloat but the type checker thinks that you have Basic rather than Expr. In that case the fix is about trying to get the type checker to understand that you have Expr rather than Basic rather than trying to get the type checker to (incorrectly) think that Basic is a subtype of SupportsFloat.

Without any demonstration code it is difficult to say where the problem might be though.

2 Likes

You’re right about the float of course, my bad.
The question still stands though. It is a generic question - how to partially override type hints.

That wouldn’t happen, because sp.sympify would be declared in the stub as well, no?

sympy has its incomplete annotations defined directly in it sources. There are no stubs.

I want to override some of the hints without modifying sympy. I want to stub a class here or there or even just one method.

Yeah, that’s what I meant. Make your own stubs (and perhaps later make a PR for it), so you make a sympy.pyi. Type-checkers will prefer the stubs in .pyi’s, if you import them in a if TYPE_CHECKING block.

If you only want to stub some thing ls though, it’s best to have the .pyi import the rest from the runtime implementation/ the other stus that are correct. Only overwriting stubs of a single method is not really possible, unless you have some

class Name(runtime.Name):
    def method_to_overwrite(...): ...

in the stub.

1 Like

Currently (sympy==1.14.0) SymPy doesn’t ship a py.typed, and it’s type coverage (of the inferred public api) is at 3.0% (see the typestats dashboard for details). But as you know, without a py.typed even those 3% annotated symbols won’t be used by static type-checkers.

Is there a plan (or wish) for adding a py.typed to SymPy and/or increasing this type coverage? Because if so, I’d be willing to help out with that :slight_smile:.

EDIT: I see that since the last SymPy release a py.typed has been added, nice.

2 Likes

Yes, the py.typed file is there and will be there in the next release. It was actually added but then removed again because it meant that SymPy users using vscode and pylance would have problems with pylance ramping up gigabytes of memory and using many minutes of 100% (single core) CPU. I think that at least based on my own use of pyright the situation has improved enough to add the py.typed file back but a new release is needed. There is also a lot more type coverage in the development branch that is not yet released (this is why it is possible to add py.typed back).

Still though it is a work in progress and it really needs users such as @WizardUli to open at least issues if not PRs to scratch their own itch for particular annotations rather than working around the problems in downstream code.

I just checked the coverage of the sympy main branch (uvx typestats check sympy) and it reports 17.54% type coverage. That’s pretty impressive progress, especially if you consider that there are 31,017 (!) typables in the public API of sympy in total. For comparison, there are 13.4k public typables in scipy-stubs, and 5.4k in numpy.