-
Notifications
You must be signed in to change notification settings - Fork 193
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
[107] Use Python 3 type annotations #1665
base: master
Are you sure you want to change the base?
Conversation
Thanks for triggering that discussion. I think that @paugier will have an opinion on this. |
First naive questions: @seertaak did you have a look at Transonic and how one can use Pythran with Python 3 type annotations with it? With your proposal, how would you define array types? In strings as in It would be nice to present examples of what your proposal improves and how things would be written. A comment: multi-signatures are a bit more precise than annotations as soon as one uses more than one overloads. See for example the difference between:
and
In this case, it seems anecdotal but when there are more arguments, it can make a huge difference in term of compilation time. One needs to be clear how annotations are converted to signatures. To express the former in Transonic one can write
In contrast,
should correspond to the later. |
PR Goals
30,000ft View
Support/Limitations
Misuse: checking#pythran export foo(str)
def foo(xs: str):
return xs
# Error produced: "E: Type annotations don't match pythran spec directive for 'foo': expected ((<class 'int'>,),); got ((<class 'str'>,),)."
#pythran export bar
def bar(xs: ndarray[int, :, uint32]):
return xs
# Error produced: (Still needs some work e.g. replacing list for uint32.)
# Exception: Invalid type argument to template type ndarray; expected slice or int literal, got: uint32 of type <class 'type'>. Primitive TypesEvery primitive type except float128 and complex256. For those, I got an undefined error in numpy; not sure why. def times_two(x: int):
return 2*x
def twice(x: str):
return 2*x
def blah(z: float32):
return 2.0*x Compound TypesHere's what's supported: import numpy as np
#pythran export foo
def foo(xs: list[int]) -> list[int]:
return [2*x for x in xs]
#pythran export bar
def bar(strs: set[str]) -> bool:
return 'hello' in strs
#pythran export baz
def baz(x: tuple[int, str]) -> str:
return str(x[0]) + x[1]
#pythran export bingo
def bingo(M: ndarray[float32, :, 2]) -> ndarray[float32, :]:
print(len(M))
x = np.zeros(len(M))
for i in range(len(M)):
x[i] = sum(m_i for m_i in M[i, :])
return x Design Questions
|
About the difference with what we can currently do with Transonic-Pythran (I'm just curious) ? |
First, transonic looks really interesting, congrats on that project. It goes without saying that I find pythran quite delightful. Superficially, the difference is that I eschew the string syntax you cite in favor of a more "standard" (but perhaps longer winded) notation reminiscent of both Python and C++. Also, I'm submitting this PR for Pythran; I'm not sure if code is shared between Pythran and Transonic....
Apart from C (?) arrays, my implementation supports the gamut of types supported by the spec syntax itself. Hopefully this answers your question. Or maybe you wonder if the typing is really recursive? (Can you make a list of list? Yes). FYI: I have of course thought about extending the type system of Pythran to include records (MLsub with special accommodation for sized arrays a la Futhark - could be cool). But as mentioned before, I was trying to keep this PR focused.
The following would work: def fun(xs: ndarray[float, :])
# next, how I would do arrays
def fun(arr: array[float, 10]) # fixed length, stack-allocated.
def fun(arr: array[float, :]) # in effect std::dynarray |
Thanks for the detailed answers! One quick note before I dive more in the details:
already means you're exporting a global variable named
I'm obviously open to alternative 👍 And again, thanks for triggering this delightful discussion ;-) |
Thanks for pointing this out. I'm happy to use your proposed syntax. Are you ok with the use of To manage expectations, the next slab of time I'll have will be this weekend. |
I'm ok with def bingo(M: ndarray[float32, :, 2]) -> ndarray[float32, :]: without the proper imports, this line is no longer valid, you'll get unbound identifier for |
But then you need Pythran to run the code even when it's not compiled, isn't it? |
yeah :-/
|
Questions About Implementation@serge-sans-paille if I understand correctly, what you would like is that:
Please correct me where I'm wrong 😄 I actually thought of this approach myself, but had already begun work on the parsing method I used, and wanted not to get bogged down. However, what I like about the approach I think you suggest is that it keeps you honest: by evaluating the type annotation using Python itself, you ensure that the module can be parsed and evaluated using only Python (and of course the Pythran module it refers to - see next point!). Type Annotations Implies Pythran Dependency
You would need to import the relevant Pythran module, yes, but the alternative embodied by my current changes is that you need to compile the module using Pythran. If you really don't want to require Pythran at all, then there are two options:
My opinion is that the import to Pythran's typing module is not too onerous. Rules Surrounding Pythran Comment Directives When Type Annotations ExistIt would be great if you could clarify the following:
For now those are all my questions. Going forward it would make a lot of sense for type annotations to permit return types to be specified, but that's for another day. |
Hey @steertaak, what's the status of this PR? Looks like it's in pause, which is fine with me - I mean, there's no hurry, just wanted to get some news ;-) |
With NumPy v1.20, there is now an official way of annotating types: https://numpy.org/devdocs/release/1.20.0-notes.html#numpy-is-now-typed |
I'm a bit skeptical about using To use type annotations for Pythran and other Numpy accelerators, one needs much precise concrete types, and also fused types. See what is doable with |
NB. This is a WIP. I am creating this PR to get feedback relatively early.
Issue 107 calls for the use of PEP 484 type annotations in lieu of the Pythran's comment directives as a means to convey function signature to the Pythran compiler. This PR offers an experimental implementation of these.