Diary 2019-03-30

By Max Woerner Chase

So, I don't remember explaining what it is that I'm trying to add to Jedi. I don't remember a lot of things. I also remember a lot of things. ... Well then. Anyway, Jedi is a Python library that provides auto-completion facilities for Python code; various text editors integrate with it. Among its features are determing a value's expected type from context, and providing suggestions for field access based on that type. For example, you could have a function parameter annotated as int, and it would suggest methods from the int type if you typed a dot after it.

Now, Python 3 has been adding various features around gradual typing, various ways to define types outside of just providing stuff like str or int. Among the facilities offered by the typing module, are the ability to statically define subclasses of types, that aren't visible dynamically. In other words, at runtime, they are no-op functions, but according to static analysis, they are subclasses of a particular type. This could be used to allow the type checker to reason about stuff like sanitized data, or restricted subsets of a type.

However, these features do not play nicely together. Jedi sees the runtime nature of the NewType, instead of treating it as a cast. As such, the inferred type of the input is the inferred type of the output, and for function parameters, it infers no type at all.

I first found out about this behavior from a discussion on StackOverflow, where I was surprised to discover that things didn't work as I expected, and they were disappointed. I entered an issue on the bug tracker, offered to help, and then got horribly distracted. For so long, that the relevant development moved to a feature branch specifically devoted to improving integration with typing.

Looking over what there is right now, here's how I think I'm supposed to implement things:

A NewType is a callable returned from a callable. I think this means that I need to define two contexts: NewTypeClass for NewType itself, and NewType for its return values.

As far as actually implementing this stuff... I got started, then realized that this stuff is confusing to me because I lack context, so now I'm reading Jedi Development to try and get filled in a little. Um, oops, I feel like there was less there than I expected.

Here's where I'm at:

The first argument to NewType is a str, and the second argument is "anything that we consider equivalent to a class". The result is a context that has a name given by the first argument, and acts like a class, where the constructor takes one argument, of the type of the second argument.

Oh well, I'll keep trying to understand this. For now, good night.