-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
[ENH] Implement "typing.Optional[]" and give it Python semantics ("not None" vs. "or None") #3883
Comments
typing.Optional[]
and give it Python semantics (not None
vs. or None
)
Some of the problem here is identifying I'm trying to get this to work for #3400. If I get something satisfactory I'll try to make a PR for it on its own, because it'd probably be useful here too. |
@da-woods Should we allow this at all? Because it seems that the only real cases are import typing
var: typing.Optional[...] from typing import Optional
var: Optional[...] And we can still just watch the |
I don't see why not. You have to track it anyway because users could name their own global variables |
I don't mind, I just suggested an easier way. |
@matusvalo yes I think it should |
Is it complete, though? I also suggested to change the default semantics of |
Ah, right. It seems that this was also implemented: cython/Cython/Compiler/Nodes.py Lines 950 to 973 in 102366d
|
One issue that I found is that (as before) this only applies to Python calls. Should we make this fail on the caller side? cdef func(x: list): ...
func(None) It feels a bit mixed. Here, the developer is usually in charge of the calling code. User provided What do you think? |
Oh, and we probably also need some error tests for things like |
I'm not completely sure what the right thing to do is, but it should definitely be tested and documented! Having different rules for cdef functions feels a bit obscure to me.
|
One more tricky thing: |
…unc(x: Optional[list])". See cython#3883
I have implemented |
Yes.
Sort-of, yes. I mean,
Turns out, it already is, because
It looks like |
…d complaining about "or None", which wasn't the actual syntax construct on user side. See #3883
Turns out that this is difficult to handle. The type analysis converts explicit type references like |
… "Optional[int]" etc. interprets "int" as (valid) Python int type and not (invalid) C int type. See #3883
I looked into the test failures that I introduced in the master branch (sorry for that) and one of the issues is this test: cython/tests/run/pep526_variable_annotations.py Lines 187 to 189 in 7914e3b
As you can see, it assumes that x: Tuple[int, float] refers to a tuple of C int , C float . This is a wrong assumption. It sees a Python type declaration and should infer (Python int , Python float ) instead (or C double , for that matter). Otherwise, it would incorrectly constrain the value range of the first tuple item, if this comes in from Python code.
I've reverted my changes in master and will see how I can fix this up in a separate branch. |
It was definitely my intent that typing.Tuple should be able to produce C-tuples (and I think this is a reasonable thing to do). I think here it shouldn't though, because it should require |
So my view:
These subscripted types can end up with fairly deeply nested types, which we want to detect these in. That suggests we'd be better passing an |
Yes, nesting is an issue, but also e.g. |
… "Optional[int]" etc. interprets "int" as (valid) Python int type and not (invalid) C int type. See cython#3883
… "Optional[int]" etc. interprets "int" as (valid) Python int type and not (invalid) C int type. See cython#3883
How should these be handled in a |
I also had to stop and think about that for a moment, but the file type should make no difference here. The reason for the different meanings is that |
|
Correct as it stands, but it doesn't need to stay that way. We could certainly start using |
In fact, we could consider the |
Just as another thought, this could be a place where C++ developers might want to use To the original question about whether file type should affect type interpretation, this could be posed with |
I'd be reluctant to start substituting C++ containers for Python types. There's two set implementations for C++ ( I think I agree that file-type shouldn't affect interpretation. Mainly because I think it'd be a complicated rule that'd be hard to explain and end up confusing people (so it'd need a very good justification why it's needed) |
Sorry didn't mean to send us down a rabbit hole with C++. Just thinking of other cases where |
… "Optional[int]" etc. interprets "int" as (valid) Python int type and not (invalid) C int type. See cython#3883
By the way, I see in 13f8cd7 that you've supported implicit optionals (non-optional but with
I think it would be better thus to not support it, but I'm maybe too strict. |
…cit "typing.Optional[]" declaration. See #3883
… "Optional[int]" etc. interprets "int" as (valid) Python int type and not (invalid) C int type. See cython#3883
Thanks for the notice. I'm sure there's a considerable body of code out there by now that makes use of this 'obvious' simplification, so a warning seems better than a syntax error. |
… "Optional[int]" etc. interprets "int" as (valid) Python int type and not (invalid) C int type. See cython#3883
* Check for "Optional[ctype]" earlier because we need to make sure that "Optional[int]" etc. interprets "int" as (valid) Python int type and not (invalid) C int type. See #3883 * Fix typing assumptions in PEP 526 variable annotations test: in a Python type annotation, "int" means Python int and "float" means Python float, not the C types. * Use a context manager to make it explicit in annotation type analysis when C types are allowed, and when Python types are required or expected. * Generalise the concept of equivalent Python and C types for more efficient type inference: PyFloat/double, PyBool/bint, PyComplex/double complex. * Refactor analyse_type_annotation() to prepare the extraction of type modifiers (as opposed to special types). See discussion in #4606 (comment) * Refactor handling of "typing.Optional", "dataclasses.InitVar" etc. annotations to move them into the declared Entry during type analysis and keep only the bare type in the type system. * Force ClassVar[...] types to be object types. * Add a warning when users define a ClassVar[] with a non-Python type. See #4606 (comment) * Provide a helpful warning when users write plain C types in a non-C annotation context. * Only consider Python object item types from list/tuple as self.type in IndexNode since that will be the result of the index access. Coercion needs to happen externally, then based on the type inference. * Ignore Python annotation type "long" since it almost certainly does not refer to PyLong but to C long. Issue a warning to make users aware of it. * Fix PEP-526 test by working around incomplete type inference, but leave FIXME comments.
This issue is largely done I think? |
I think so, too. Let's close it. |
In Cython,
def func(list arg)
allowsarg
to beNone
. In Python's PEP-484typing
universe,def func(arg: list)
excludesNone
and passingNone
requires the spellingdef func(arg: Optional[list])
.Given that
Optional[…]
exists, we could change the type analysis of PEP-484 argument annotations to excludeNone
by default (i.e. interpret them as ifnot None
was given), since this it is a common source of mistakes (see #2696). The use ofOptional[]
would then be interpreted asor None
.This would probably not apply to variable annotations. While PEP-526 doesn't seem to mention the topic anywhere explicitly, it seems hard to prevent variables from being set to None, and it has a runtime impact to prevent that case. Also, it does not seem very useful to actively prevent users from setting variables to None.
Also note that there is the issue of subtypes, which Python typing allows but Cython typing rejects. This difference would probably remain.
The text was updated successfully, but these errors were encountered: