Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How should we annotate functions that forward to their superclass? #1471

Open
NeilGirdhar opened this issue Sep 18, 2023 · 5 comments
Open
Labels
topic: feature Discussions about new features for Python's type annotations

Comments

@NeilGirdhar
Copy link

NeilGirdhar commented Sep 18, 2023

Consider this real code:

from typing import SuperKwargs

class InferenceManager(Generic[T]):
    @override
    def __init__(self,
                 *,
                 default_trajectory: T,
                 progress_manager: None | ProgressManager,
                 wandb_run: None | Run
                 ) -> None:
        super().__init__()
        self._progress_manager = progress_manager
        self._results: list[T] = []
        self._trajectory = default_trajectory
        self._wandb_run = wandb_run


class TrainingInferenceManager(InferenceManager[RLTrainingResult]):
    def __init__(self, training_result: TrainingResult, **kwargs: SuperKwargs):
         self.training_result = training_result
         super().__init__(**kwargs)

If we want full annotations for TrainingInferenceManager.__init__, we currently need to duplicate all of the superclass's parameters. I suggest adding typing.SuperKwargs that stands in place of them.

(This could be made more complicated by allowing the child class to synthesize some of the parameters.)

Related: python/mypy#8769

@NeilGirdhar NeilGirdhar added the topic: feature Discussions about new features for Python's type annotations label Sep 18, 2023
@erictraut
Copy link
Collaborator

If you're using a smart editor or language server, it should take little or no effort to duplicate the signature when overriding a method. For example, with pylance installed in VS Code, you can type def __init__, then hit tab, and the entire signature of the base class will be copied along with a call to super().__init__(). I realize that's not quite what you're asking for here, but I mention it in case you weren't aware that this functionality existed.

@NeilGirdhar
Copy link
Author

Thanks @erictraut, that's a good point. I use NeoVim, which afaik doesn't have this functionality. I'm sure you're aware, but just for any other readers, the limitations of copying the base class signature include:

  • there may be more than one base class,
  • the base classes can change, which leads to churn in all derived class signatures, and
  • as in the example above, the base class is generic, but the derived class isn't, so the editor would have to do the generic type substitution.

@kwsp
Copy link

kwsp commented Sep 20, 2023

@NeilGirdhar Chiming in: I use NeoVim too, and with these plugins, I do get the def __init__ tab completion on a child class

  use {
    "williamboman/mason.nvim",
    "williamboman/mason-lspconfig.nvim",
    "neovim/nvim-lspconfig",
  }

Using mason.nvim I installed pyright with LspInstall pyright. Mason plugs pyright into NeoVim's native LSP framework.

@kwsp
Copy link

kwsp commented Sep 20, 2023

On this topic, I think there is a need for a way to forward parameters annotations in general, not just for the purpose of inheritance. For example, I often write pure helper functions that are called inside a method that take the same parameters as the method.

@gwerbin
Copy link

gwerbin commented Dec 20, 2023

If you're using a smart editor or language server, it should take little or no effort to duplicate the signature when overriding a method

A plain-text copy of another library's source code is a flaky error-prone thing to maintain, even if it is possible to generate one.

You might end up having to import a big pile of weird internal details that the upstream library uses in their type annotations that might break at any time, and are otherwise irrelevant to your application.

For example, consider the case of writing a type stub for geopandas.GeoSeries, which inherits from pandas.Series. The problem is that pandas.Series.__new__ has 6 parameters and 4 overloads, and several of those parameters are themselves complicated internal-only things that have no stability or interface guarantees.

Similarly, imagine a case where I'm writing my own subclass of Series, and all I want to do is define a new method and add an extra optional parameter to __init__. Ideally I'd be able to forward the types of *args, **kwargs to the parent class and not have to maintain my own copy of the entire signature.

I think the above cases are common enough and painful enough that something like SuperKwargs would be very much appreciated by many people.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

4 participants