Skip to content

Allow overriding own code with stubs #2502

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

Closed
rtpg opened this issue Nov 28, 2016 · 10 comments
Closed

Allow overriding own code with stubs #2502

rtpg opened this issue Nov 28, 2016 · 10 comments

Comments

@rtpg
Copy link
Contributor

rtpg commented Nov 28, 2016

mypy currently has a bit of trouble with some of the more complicated types out there, especially when it comes to metaprogramming.

It would be pretty useful if I can provide a stub that would override a class defined in my own code, in cases where mypy fails to generate the proper type for a class.

For example, have a file like:

# mypy: ignore-type
class C:
    
    a = 3




def f(c: C) -> str:

    return c.a  

with the stub file being:

class C:

    a = ...  # type: str

(Here f would type check because the type lookup for C would happen through the stub, not the implementation)

This will let some people properly type complex objects generated by tools like ORMs.

I tried simply providing a stub for C along with the implementation, but currently it seems like the implementation's type inference works here.

@rwbarton
Copy link
Contributor

The Zulip project does this, see https://github.com/zulip/zulip/blob/master/zerver/lib/request.pyi which is a custom stub file for https://github.com/zulip/zulip/blob/master/zerver/lib/request.py. It works because Zulip has a script to run mypy (https://github.com/zulip/zulip/blob/master/tools/run-mypy) that builds a list of files to pass to mypy and filters out .py files that have a matching .pyi file. (That means that mypy will never type check the actual .py file; but presumably the .py file is doing things that mypy doesn't understand anyways, so it's reasonable to minimize the amount of code that has to go in the .py file and accept that it will be unchecked.)

It might be sensible to make this mypy's default behavior: prefer .pyi files to .py files even in the code to be checked (rather than only in its imports).

@gvanrossum
Copy link
Member

gvanrossum commented Nov 28, 2016 via email

@rwbarton
Copy link
Contributor

I was more thinking about the case of passing a package(?) name to mypy, like mypy mypy.

@gvanrossum
Copy link
Member

gvanrossum commented Nov 28, 2016 via email

@rwbarton
Copy link
Contributor

Oh hmm. In that case I don't understand what situation the OP had where mypy wasn't working as expected.

@gvanrossum
Copy link
Member

My guess he's imagining that the stub and the .py file would be combined somehow. @rtpg can you clarify what you are trying to do?

@rtpg
Copy link
Contributor Author

rtpg commented Nov 29, 2016

So my understanding of how mypy currently looks up types is:

  • first, look at all the types provided from the py files passed in. Use the type generated from the code if present
  • If the type is not found there, look in stubs (through MYPYPATH for example).

I would like to be able to exclude on a class/type basis, rather than a file basis, because I have files with class definitions and functions that I would like to be checked by mypy.

The issue with the zulip mechanism is that by excluded my entire py file, I exclude C but also f, and would have to stub out that file too. Though the zulip mechanism works, it requires isolating parts of code that you want type-checked from code that you want to be replaced by stubs.

By being able to say "this object should not be looked at by mypy for the type definition", I can stub in parts of a file that are trickier without needing to do refactors of my code itself.

An alternative solution for my case would be to re-export:

  • move example.C to non_checked.C
  • provide a stub file for non_checked.C, while re-exporting C in example

I'll see if this works for my use case.

@ambv
Copy link
Contributor

ambv commented Nov 29, 2016

@rtpg What you want is already possible on module level. The trick is to invoke mypy to check modules and not files and set MYPYPATH such that is has multiple directories. Your stub directory should come before your source directory. Then you're working on module paths and imports, so you can write a name.pyi file to stub name/__init__.py in your source, and vice versa, including imports that are dynamically created.

But it won't be possible on class level, this would be rather confusing for the reader of the code. The file boundary is pretty obvious to explain and easily visible with verbose logging. A class/type boundary, I don't see how that could be expressed.

@rwbarton
Copy link
Contributor

For "stubbing" a single class, I suppose you could use if MYPY: around the class definition and give the "stub" in the mypy branch.

@JukkaL
Copy link
Collaborator

JukkaL commented Jan 28, 2020

I hope that the ideas discussed above are good enough. Closing due to lack of activity.

@JukkaL JukkaL closed this as completed Jan 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants