pgi-docgen
pgi-docgen copied to clipboard
[WIP] Stub generation
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.).
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 (??)
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.
Feel free to merge whenever you want. You should have a repo invite so you can push directly if you want.
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 toInitiallyUnowned
- 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.
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?
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.
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.
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 frompgi
(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.
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.
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 withTypePlugin.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.
Maybe the new https://github.com/python/mypy/pull/6830 would help by just ignoring all the errors in the stubs.
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.
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.
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
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.
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?
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).
There is manually written stubs here. I guess that is enough
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