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
create type hint stub files for module torch #12500
Conversation
This is more a basis for discussion that a ready solution, as it does lots of funny things, and for many of them a better solution will be found. - Initial stab at creating a type torch/__init__.pyi . - We only do this for Python 3 because we want to use type hint introspection. - So far, we only aim at doing this for torch functions and torch.Tensor. - We need to import the newly build torch. Thus we do this at the end of the build. We use os.fork to only import the module in a child process. - We use an annotate decorator to be able to put type hints on the native python functions in a way that a) they're available in the usual place for Python 3 b) we stay Python 2 compatible - Some annotatons in torch/functional.py are provided as examples, but the remaining ones still need to be done. This could end up fixing pytorch#7318
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
tools/pyi/gen_pyi.py
Outdated
'double': 'float', | ||
'Generator *': 'Generator', | ||
'Generator*': 'Generator', | ||
'std::vector<Tensor>': 'Tuple[Tensor, ...]', |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
tools/pyi/gen_pyi.py
Outdated
'Layout': 'layout', | ||
'void*': 'int', # dataptr | ||
'std::string': 'str', | ||
'real': 'float', |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
- Add manual tensor() annotation, thank you, @elliotwite. - Create class stubs for device etc. - Improve type mapping. Thank you, Simon, for the review comments.
tools/pyi/gen_pyi.py
Outdated
'std::string': 'str', | ||
'real': 'Union[float, int]', | ||
'accreal': 'Union[float, int]', | ||
'IntegerTensor': 'Tensor', |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
tools/pyi/gen_pyi.py
Outdated
|
||
def arg_to_type_hint(arg): | ||
name = arg['name'] | ||
if name == 'from': # keyword... |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
Question: what do you think is a good way to test this? Maybe pick some functions, and construct inputs basing on arg type, and then assert that it doesn't throw error from arg parser (it may still error in later stages due to things like shape mismatch)? |
We'll definitely need some sort of testing strategy for this, otherwise it will bitrot faster than you can say leroy jenkins. |
|
||
# annotation decorator to get annotations in a way that is compatible | ||
# with both Python 2 and 3 | ||
def annotate(ret, **kwargs): |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
tools/pyi/gen_pyi.py
Outdated
needed_modules = set() | ||
|
||
|
||
def type_to_python(typename): |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
Re testing: So the type hints should ideally have two properties:
|
tools/pyi/gen_pyi.py
Outdated
|
||
|
||
def do_gen_py(build_lib_path): | ||
while '' in sys.path: |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
tools/pyi/gen_pyi.py
Outdated
decls = [d for d in decls if d['name'] != fname + '_out'] | ||
for decl in decls: | ||
skip = 'Type' in [a['dynamic_type'] for a in decl['arguments']] | ||
if not skip: |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
return name + ': ' + typename + default | ||
|
||
|
||
def generate_type_hints(fname, decls, is_tensor=False): |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
tools/pyi/gen_pyi.py
Outdated
python_returns_s = python_returns[0] | ||
type_hint = "def {}({}) -> {}: ...".format(fname, python_args_s, python_returns_s) | ||
numargs = len(decl['arguments']) | ||
have_vararg_version = (numargs > 0 and decl['arguments'][0]['dynamic_type'] in {'IntList', 'TensorList'} and |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
OK, so I briefly skimmed the generation code, and I think the best thing we can do to make this presentable is to do some Declarations.yaml cleanup, which should simplify a bit of the hacking around you had to do here. #12562 records some overall directions we want to take here, but probably the most important prereqs for this patch are:
|
So what does the #12562 washlist mean for progressing here? |
Let me look again at the code and work out exactly what would be affected by the changes.
Yeah, I don't personally object to it. It seems like a quite nice way to add the annotation.
This sounds like a great idea. |
tools/pyi/gen_pyi.py
Outdated
return type_hints | ||
|
||
|
||
def parameters_from_signature(sig): |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
These spots look like they would make Declarations.yaml refactoring harder Line 56 in a327e18
Line 188 in a327e18
Don't want to hard-code _out handling and inplace handling; should be centralized. Line 60 in a327e18
Type is going away. This one's pretty harmless though, easy enough to fix once Type is killed. Line 65 in a327e18
Hard-coded handling of self. Maybe this is OK and we'll keep this in the end. CC @zdevito Line 75 in a327e18
Hard-coded TensorOptions expansion Line 87 in a327e18
I actually have no idea what is going on with varargs. |
The |
setup.py
Outdated
class create_pyi(distutils.command.build.build): | ||
def run(self): | ||
print("-- Building .pyi --") | ||
if sys.version_info[0] == 3: |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
* create type hint stub files for module torch This is more a basis for discussion that a ready solution, as it does lots of funny things, and for many of them a better solution will be found. - Initial stab at creating a type torch/__init__.pyi . - We only do this for Python 3 because we want to use type hint introspection. - So far, we only aim at doing this for torch functions and torch.Tensor. - We need to import the newly build torch. Thus we do this at the end of the build. We use os.fork to only import the module in a child process. - We use an annotate decorator to be able to put type hints on the native python functions in a way that a) they're available in the usual place for Python 3 b) we stay Python 2 compatible - Some annotatons in torch/functional.py are provided as examples, but the remaining ones still need to be done. This could end up fixing #7318 This was backported from #12500 but with tests removed and the stub file checked in directly, so we don't have to also make sure all build shenanigans work. Master will be properly tested. The stub file was generated by running 'python setup.py create_pyi' and then copying the generated pyi file in the build directory (find -name *.pyi) to torch/ * Ignore pyi in flake8 Signed-off-by: Edward Z. Yang <ezyang@fb.com> * Real fix for lint error Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
After a lot of whacking, the type annotation script no longer requires |
Awesome stuff, @ezyang . ❤️ Probably would have been easier to not base it on my feeble attempts. 😕 |
Let's be clear now, your diff helped a lot :) Would have been 10x more work without it. |
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Ugh, CI failure doesn't repro locally. Time to fire up the Docker image, I guess... |
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
So, in the end, you were right! The problem is specific to when you install PyTorch, because mypy treats installed packages differently from local packages. It will refuse to attempt to typecheck using installed packages unless they are registered on typeshed, which explains why the imports cannot be found. Your symlink trick solved the problem, because it made the package look local again. There doesn't seem to be a way to otherwise force mypy to treat the package as typecheckable when it's not registered on typeshed. I think I am just going to resurrect this code verbatim with a comment. |
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
* create type hint stub files for module torch This is more a basis for discussion that a ready solution, as it does lots of funny things, and for many of them a better solution will be found. - Initial stab at creating a type torch/__init__.pyi . - We only do this for Python 3 because we want to use type hint introspection. - So far, we only aim at doing this for torch functions and torch.Tensor. - We need to import the newly build torch. Thus we do this at the end of the build. We use os.fork to only import the module in a child process. - We use an annotate decorator to be able to put type hints on the native python functions in a way that a) they're available in the usual place for Python 3 b) we stay Python 2 compatible - Some annotatons in torch/functional.py are provided as examples, but the remaining ones still need to be done. This could end up fixing #7318 This was backported from #12500 but with tests removed and the stub file checked in directly, so we don't have to also make sure all build shenanigans work. Master will be properly tested. The stub file was generated by running 'python setup.py create_pyi' and then copying the generated pyi file in the build directory (find -name *.pyi) to torch/ * Ignore pyi in flake8 Signed-off-by: Edward Z. Yang <ezyang@fb.com> * Real fix for lint error Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Oh my god it passed all the tests LOL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ezyang is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
I'm curious: why didn't you just annotate |
@vsiles For a pretty silly reason, actually: the original patch @t-vi wrote didn't do that, and when I tried it, PyCharm shows up the module as This isn't set in stone, esp. if people don't mind the originating module look ugly. But that's the reason. |
We have:
works on.
done in torch/init.pyi.in
For me, PyCharm (the non-paid one) didn't seem to indicate errors in the .pyi when opening and seemed to be able to get the type hint for the few functions I tried, but I don't use PyCharm for my usual PyTorch activities, so I didn't extensively try this out.
An example of a generated PYI is at this gist. https://gist.github.com/ezyang/bf9b6a5fa8827c52152858169bcb61b1
Original summary:
This is more a basis for discussion that a ready solution, as it does lots of funny things, and for many of them a better solution will be found, but to facilitate discussion, I'm putting this out.
After many improvements, this could contribute to fixing #7318.
We have
torch/__init__.pyi
.We use os.fork to only import the module in a child process.
a) they're available in the usual place for Python 3
b) we stay Python 2 compatible
For me, PyCharm (the non-paid one) didn't seem to indicate errors in the .pyi when opening and seemed to be able to get the type hint for the few functions I tried, but I don't use PyCharm for my usual PyTorch activities, so I didn't extensively try this out.
An example of a generated PYI is at this gist.