Skip to content

Feature: add signature exposure for static inference - #808

Open
cvanelteren wants to merge 13 commits into
mainfrom
fix/static-parsing
Open

Feature: add signature exposure for static inference#808
cvanelteren wants to merge 13 commits into
mainfrom
fix/static-parsing

Conversation

@cvanelteren

Copy link
Copy Markdown
Collaborator

Ultraplot does a lot of runtime composition (lazy loading, dynamic dispatch, and shared doc merging), which makes static analysis difficult because analyzers see only source-level declarations, not the final runtime-expanded API. The lazy loader compounds this by delaying object/materialization of the public surface. On top of that, _obfuscate_parameters historically replaced visible signatures with compact (**kwargs) forms to keep docs manageable, which also removed concrete parameter metadata from inspect.signature, so tools like Pylance had less to work with for hovers/call tips.

So the concrete problem was a combo of:

  1. runtime indirection (lazy loading),
  2. runtime signature/docstring composition, and
  3. signature obfuscation for docs at the callable object level.

This PR separates the two processes by keeping a copy for the docs themselves while using a process that static analysers like Pylance can work with.

@codecov

codecov Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.59664% with 20 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
ultraplot/tests/test_stubs.py 88.00% 9 Missing and 6 partials ⚠️
ultraplot/tests/test_docstring_helpers.py 93.33% 3 Missing ⚠️
ultraplot/internals/docstring.py 92.30% 0 Missing and 1 partial ⚠️
ultraplot/tests/test_kwargs_helpers.py 87.50% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

Does this work @munechika-koyo ?

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

TODO: get an editor with pylance

@cvanelteren
cvanelteren marked this pull request as ready for review September 2, 2026 15:16
@munechika-koyo

Copy link
Copy Markdown

I checked how the static type-checking tool (pyrefly in my case) behaves in the PR environment.
The results are below:
Screenshot 2026-09-03 at 9 35 29
Screenshot 2026-09-03 at 9 18 18

Since the docstrings are dynamically created when importing ultraplot at runtime, is it difficult for such tools to handle this information statically?

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

From my understanding yes. Custom stubs would work but that is very not handy to maintain.

@cvanelteren

cvanelteren commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

So had a bit more digging. The solution it seems is that one would have to generate and comit the stubs to the repo in order for it to work with the static viewer properly. This is also how mpl does it.

@munechika-koyo

munechika-koyo commented Sep 3, 2026

Copy link
Copy Markdown

It's true that management costs might go up, but that seems like the better option for generating stubs in a runtime environment, for example, using mypy's stubgen tool.

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

Can you check the editor with the stubs added? (30k jeezzzz)

@munechika-koyo

munechika-koyo commented Sep 3, 2026

Copy link
Copy Markdown

In my environment with pyrefly, I couldn't see the correct generated docstrings on hover because it prioritizes using docstrings in *.py files, not .pyi files.
I submitted the issue to pyrefly: facebook/pyrefly#4803.

Anyway, there appear to be many Incomplete types in .pyi files.

def Colormap(*args: Incomplete, name: Incomplete=None, listmode: Incomplete='perceptual', filemode: Incomplete='continuous', discrete: Incomplete=False, cycle: Incomplete=None, save: Incomplete=False, save_kw: Incomplete=None, **kwargs: Incomplete) -> Incomplete:

Were they caused by automatic generation?
Is it possible to fix the types for them?

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

Most of the codebase is not type annotated yet and the automatic inference fallsback to Incomplete I think

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

Wouldn't this solve all the issues: https://marketplace.visualstudio.com/items?itemName=KiidxAtlas.python-hover

@munechika-koyo

Copy link
Copy Markdown
Screenshot 2026-09-03 at 16 34 57 Looks like it doesn't solve it...

@cvanelteren

cvanelteren commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

hmm annoying. help ofc works fine

@cvanelteren
cvanelteren marked this pull request as draft September 3, 2026 14:48
@cvanelteren
cvanelteren marked this pull request as ready for review September 3, 2026 15:20
@cvanelteren

cvanelteren commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

I added a dynamic inspector prior to dumping the stubs to expand the stubs, does this work @munechika-koyo ?

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

Note there is another small issue that proplot clearly intended the docs to be used as a replacement. So many of the docstrings are near novels.

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

Nvm I noticed I broker a bunch of stuff for myself now. I will fix that first before I ping again.

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

Ok I got the tool complete to work again in zed:
image

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

I had to run this

  pip install --force-reinstall --no-deps \
    --config-settings editable_mode=compat \
    -e /home/casper/projects/ultraplot

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

Ok this is turning more of mess than I wanted it to be. I knew the doc strings were complicated in pro/ultraplot but the extension is something that should be addressed. I would love to go back and just make it verbose and remove a bunch of aliases (we have way too many I think) but this would be so much work..

@munechika-koyo

munechika-koyo commented Sep 4, 2026

Copy link
Copy Markdown

When hovering over scatter,
Screenshot 2026-09-04 at 11 52 16

When hovering over the underwaveline,
Screenshot 2026-09-04 at 11 52 31
I also got better hovering and static type analysis, since pyrefly can suggest errors. I presume that it is because pyrefly referred to the types implemented in matplotlib.

As with many parameter aliases, I think it is important to provide clear, compatible alternatives to make it easy for matplotlib users to migrate. (I'm sometimes confused about xlocator, xformatter, xticks, xticklabels, etc.)
It might be good to be compatible with users of older versions, but reducing the available options could make it straightforward to learn how to use ultraplot.

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

I personally would love to get rid of all the aliases, I think they are unnecessary and confusing at times. But this is tricky as it was part of the public api in proplot, so dunno if we can just remove them without a deprecation phase. I find it a bit hard to judge how many people are actually using this package other than a handful. In any case, rewriting it to remove all of those aliases, would be addressing the public facing api which is never that easy to do -- some may like the aliases, some may not.

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

My count says that we have 944 aliases that can be removed in the whole package. For style alone that would be a 74 percent reduction from 179 to 47. Others are less severe.

@gepcel

gepcel commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

I use ultraplot a lot, and I use aliases a lot; I couldn't even tell which are aliases and which are not. I understand that this makes things harder for development and many other aspects. But I think it's also not easy to tell which names are more intuitive, and which save more keystrokes (which is part of ultraplot's philosophy).

Maybe you could start by not showing aliases in the documentation, rather than deprecating them all.

Is it possible to make a mapping table or a rename_helper_function that converts them before passing them into format? May this help make codes clearer?

@cvanelteren

cvanelteren commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator Author

I think one way forward is to (i) separate the aliases from the function parsing, (ii) provide a mapping table on the docs, (iii) maybe deprecate it later. The first step would fix the busy static inference here and help some with the setup. It will also be easier to deprecate (or add) aliases.

I don't want to remove stuff that is already there unless it is necessary, but some of these functions have crazy number of parameters. What do you think?

@gepcel

gepcel commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

I think with steps (i) separate the aliases from the function parsing, (ii) provide a mapping table on the docs, that will give us more time to think about deprecation, and maybe even better, it might even make deprecation less necessary.

@gepcel

gepcel commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Although I mentioned that I use aliases frequently, I probably only use a small fraction of them. However, my point is that with all 944 aliases available, different users can always pick different aliases they like best—and what suits for one person may not be the same for another. After all those long times, deperating them all will make people confusing too, because, some names they are using are aliases without them knowing it.

When we speak of alias names, we tend to assume that there is a single official name—the one that all aliases are ultimately converted to internally in the codebase. Everything else are just shortcuts that get mapped away.

However, if you go through all those official name and their aliases, you'll quickly notice that they aren't all chosen by the same logic, and are more subjective. This lack of consistency and the fact of subjective can itself become a source of confusion.

For Ultraplot (and Proplot before it), one of the goals has always been to make daily plotting easier. This is achieved not only through the format philosophy, but also through the alias system, which plays a crucial role in that ease of use.

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

I agree with that the aim should be to make plotting easier. I have tried to convince people to use ultraplot as I think it is great, but people get kinda lost in the many options that one is faced with -- the aliases don't help there. Tutorials will help ofc, but I dunno myself on exactly what magic bullet would help understanding all the keywords that are there. Potentially a rule would help. Like linewidth to lw is sensible but width to figwidth is less clear if the usage is something outside Figure.format or whatever. They can also bloat clean signatures, like what this PR shows a bit.

I think separating them so that they do exist, but the user can see a cleaned function description may work. This, combined with a map of the available aliases, would then give the best of both worlds I think.

@gepcel

gepcel commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

I think separating them so that they do exist, but the user can see a cleaned function description may work. This, combined with a map of the available aliases, would then give the best of both worlds I think.

I agree, as I said, maybe starting by less alias in documents, less confusing for new uses. Let them keep exising by separating for people get used to them.

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

I think that is a good way forward tbh.

@munechika-koyo

Copy link
Copy Markdown

I think separating them so that they do exist, but the user can see a cleaned function description may work. This, combined with a map of the available aliases, would then give the best of both worlds I think.

I also agree.
Reducing the time required to review the documents (only seeing docstrings or annotations from assisting tools) would help users focus on coding tasks.

@cvanelteren

Copy link
Copy Markdown
Collaborator Author

Merged #818 with this PR and it shows for example the complete like this now (basedpyright):

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants