pylint-dev/astroid

Make astroid typable possibily with breaking change to permit most performance increase possibility

Pierre-Sassoulas opened this issue · 3 comments

astroid is very dynamic and very hard to type. A lot of effort went into typing it, and mypy is still not activated (#1287). It prevents automated error detection in pylint and it prevent most performance possibility that always start with proper typing, be it mypyc, a partial rewrite in a rust crate (#2014) or cython.

I'm opening this discussion so we can discuss the breaking changes we need to do to make it easier to type astroid in the future.

Many node types have fields that are marked as optional when really they are required. These fields are assumed to be non-optional throughout the Astroid code, and that's a major source of type errors detected by Mypy.

For example, consider the Assert node. It has these fields:

        self.test: NodeNG | None = None
        """The test that passes or fails the assertion."""

        self.fail: NodeNG | None = None  # can be None
        """The message shown when the assertion fails."""

An assert statement without a test is not valid syntax, so the test field needs to be required. On the other hand, the fail message really is optional, so the fail field really is optional.

A symptom of the problem is the frequent appearance of # can be None comments. These show that the existing type annotations are not reliable.

Now, the reason AFAICT that these fields are all marked as optional is that the type annotations are declared in __init__ but the values for those fields are not available until postinit is called. There is an easy solution to this: declare the types outside of __init__. This has the happy side effect of making it possible to get rid of __init__ definitions altogether for many nodes, since all they do besides declaring types is calling super().__init__.

#2061 is a concrete example of the kind of change I'm talking about.