pgi-docgen icon indicating copy to clipboard operation
pgi-docgen copied to clipboard

[WIP] Stub generation

Open kaiw opened this issue 6 years ago • 19 comments

This is just a request for feedback... you probably don't want to merge this.

This PR adds actual typing information to some parts of the stub generation. Currently enums, flags, consts and functions mostly work, though there are some issues around name handling for function arguments. The goal here is to get typing annotations for mypy checking. Personally I don't care at all about the IDE completion aspect of #79 here, though they're probably related.

This is very much a work in progress, but I wanted to check whether this is of interest before I start on the actually hard stuff (e.g., figuring out out classes, GObject property annotations, etc.).

kaiw avatar Dec 21 '18 21:12 kaiw

Sure, looks good!

We probably wont need documentation for this so I'm wondering if I should add a mode that skips all the doc parsing to speed things up (??)

lazka avatar Dec 22 '18 07:12 lazka

This is approaching the point of generating usable stubs. There's still a lot of errors, but I think they're starting to get down to things like GError aliases, Liskov substitution problems, and missing Python annotations for overrides, etc.

I think I need to sit down and unify a bunch of the class/flag/enum logic, and then figure out how to handle a static list of "here are exceptions that we can't handle" to the stubbing.

...and then there should be some tests.

We probably wont need documentation for this so I'm wondering if I should add a mode that skips all the doc parsing to speed things up (??)

When setting PGIDOCGEN_CACHE, this isn't too bad for me at least... but I'm only annotating half a dozen modules. It would be nice if it was faster, but honestly I think most of the remaining time is constructing the namespaces.

kaiw avatar Dec 25 '18 22:12 kaiw

Feel free to merge whenever you want. You should have a repo invite so you can push directly if you want.

lazka avatar Dec 26 '18 18:12 lazka

Thanks!

I'm not quite there yet as far as this branch goes. The generation is useful, but the number of complaints from mypy is just too high. I'll try to find some way to reduce these and then look at merging.

Current main issues that I can think of are:

  • Figuring out how to annotate Liskov violations
  • Figuring out why some parent_instance attributes seem to not chain back to InitiallyUnowned
  • Sorting out some incorrect NoneType annotations on some of the GLib/GObject bases
  • Figure out what to do about name aliases like GObject.Object/GObject.GObject
  • Come up with a way of automatically handling classes that break things by shadowing builtins (e.g., def int(self) -> int: ...)

Once those are sorted, the stubs themselves should be fairly low on actual typing errors, and I can look at any mis-typed situations that come up.

kaiw avatar Dec 27 '18 21:12 kaiw

The generation is useful, but the number of complaints from mypy is just too high

Just wondering, are these complains also there if you use mypy to check your pygobject-using code or just when you check the stubs themselves?

lazka avatar Dec 27 '18 23:12 lazka

Just wondering, are these complains also there if you use mypy to check your pygobject-using code or just when you check the stubs themselves?

Yeah, they show up even when just using the stubs for checking application code. I haven't looked through the mypy options to see whether there's a way to turn that off yet... but I'll spend a bit of time trying to clean up the errors first anyway.

kaiw avatar Dec 30 '18 20:12 kaiw

The parent_instance problem is extremely weird. I've filed https://github.com/python/mypy/issues/6119 with a test case so fingers crossed.

Some of the Invalid type errors are caused by https://github.com/pygobject/pgi-docgen/issues/177, but I'm not sure how to fix them.

I need to figure out how to automatically handle overriding builtin cases like GLib.Rand.int(). One solution is to import builtins and use builtins.int, etc. everywhere blindly. This is probably the easiest option, so even though it makes the stubs harder to read it's probably what I'll do.

kaiw avatar Dec 30 '18 22:12 kaiw

Sorry, I haven't had a lot of time to work on this.

The current state is that the above issues are all fixed, except for the Liskov violations (that are correctly annotating the API). If I'm reading https://github.com/python/mypy/issues/5260 correctly, this is probably only happening because I'm testing with a custom MYPY_PATH, and if they were distributed as a PEP 561 package then users wouldn't see these.

The remaining major issues are:

  • Missing annotations for aliases (e.g., GObject.GObject) or things missing from pgi (e.g., GObject.Signal)
  • Functions have no default argument annotations
  • Needs testing

I can probably work around the first. The second of these... I have no idea how much work that will be. The tests I'll start on when I next get a chance to work on this.

Are the current stubs being used for anything? I'm happy to merge this as being pretty good, but I'd be worried at breakage if they're actually in use.

kaiw avatar Jan 13 '19 02:01 kaiw

Are the current stubs being used for anything?

I don't use the current stubs as they don't actually have any type hints.

I'd be very willing to use the generated stubs, though. :slightly_smiling_face:

For now I have my own stubs defined in my project, manually written, covering only the API I need.

bochecha avatar Jul 31 '19 14:07 bochecha

I still haven't had any real time or motivation to poke this much. The basics are still there, but there's many issues.

  • There are disagreements between the introspection information and about what's exposed and how (e.g., GObject.Property is a module-level alias and the stub generation doesn't pick that up).
  • The lack of any mypy-exposed typing information for GObject properties and the like makes it not very useful for some codebases (Meld suffers from this when accessing e.g., widget.props.label).
  • Closely related to the above is that all Object.new() constructors that take GObject props as kwargs have incorrect signatures.
  • GObject/GTK's inheritance hierarchy means that in pygobject, completely unrelated methods shadow each other constantly. There's many, many examples of this, but one that ends up coming up in really odd places with mypy is TypeModule.use(), which adds a boolean return that's incompatible with TypePlugin.use(); seems weird and I never use these directly, but it's in the Gio hierarchy and that's enough to cause very distracting and frankly useless type errors.

Having said that, I still run with the stubs because they've found some issues for me... they just need a bit of love and time.

kaiw avatar Aug 01 '19 23:08 kaiw

Maybe the new https://github.com/python/mypy/pull/6830 would help by just ignoring all the errors in the stubs.

lazka avatar Aug 02 '19 06:08 lazka

I've just tested in 3.7, and there the behaviour is to completely ignore the entire file. In other words, if I add # type: ignore to the top of a stubs file, it's as though the file is empty. I think the behaviour is the same in 3.8, but I'm not 100% clear and haven't tested.

kaiw avatar Aug 09 '19 22:08 kaiw

I only recently realised that the Liskov violations are split into direct subclass issues and multiple inheritance ones. I've started on a list of exclusions for the direct subclass problems, and that's silenced a lot of noise. The multiple-inheritance-based violations are workable, but I'm hitting python/mypy#7336. I think I can find a workaround, but it might be fun.

kaiw avatar Aug 14 '19 21:08 kaiw

This seems to be stalled (no activity for 6 months). Is there anything I can do to help this along?

https://github.com/pygobject/pygobject-stubs/issues/5

skewty avatar Feb 17 '20 01:02 skewty

Every once in a while I pick this up again and make a small amount of progress. Every time I've been stymied a bit by mypy assumptions/limitations, but honestly mostly by the way GTK's class hierarchy (and its mapping into overrides) works... it just doesn't match some common assumptions of type systems.

There's probably things that could be done to work around these, but it's just a lot of work to go through and figure out how to handle each individual case.

Honestly, I think the only way to make progress here is to try to use the generated stubs on a real application and just... pick the first error (or lack of error where one should be) and figure out what's going wrong. I have managed to get some small but real examples correctly type-checked this way, but it also doesn't take long to run into real issues that need thought.

kaiw avatar Feb 20 '20 23:02 kaiw

Honestly, I think the only way to make progress here is to try to use the generated stubs on a real application and just... pick the first error (or lack of error where one should be) and figure out what's going wrong.

I'm happy to help with this for my limited usage. (mostly GLib.Variant at the moment)

Should we just merge this as it is, and then we can all work together on making it better once it's easier to use?

bochecha avatar Feb 21 '20 12:02 bochecha

I'm happy to leave the merging decision to others.

In my personal opinion, I wouldn't merge this because I couldn't in good conscience suggest that someone use the generated stubs unless they were willing to contribute to fixing them. Also, the stub generation currently has no test coverage. I started writing some and immediately ran into issues that I still haven't had time/motivation to resolve.

One of the "simplest" ways to contribute is to pick a single class with a wide range of corner cases and try to isolate stub generation for that and manually check that the stubs are correct. I've been using classes like Gdk.Color because it has a mix of regular attributes and methods, weird constructor behaviour, class methods and Python overrides. Currently several of these don't work correctly (constructor behaviour and overrides, from memory).

kaiw avatar Feb 22 '20 22:02 kaiw

There is manually written stubs here. I guess that is enough

MrinmoyHaloi avatar Mar 11 '22 04:03 MrinmoyHaloi

There is manually written stubs here. I guess that is enough

Thanks for the link. Works well, but Gtk3-only. No support for Gtk4 yet

Found a little bit of discussion about Gtk4 here. No movement on it yet though

EDIT: Someone on gnome IRC alerted me to this project, and it seems to be working well for me with Gtk4. https://gitlab.gnome.org/GabMus/gi-stubgen

Run ./gen, cd into out/, and copy the gi/ directory into your site-packages. I had to install gtksourceview5 and webkit2gtk-5.0 prior to running gen.py

0x199x avatar Mar 14 '22 21:03 0x199x