Skip to content

Prohibit Callable[[...], X] #320

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

Merged
merged 6 commits into from
Nov 7, 2016
Merged

Conversation

ilevkivskyi
Copy link
Member

@ilevkivskyi ilevkivskyi commented Nov 6, 2016

@gvanrossum
Now Callable[[...], X] is accepted and treated as equivalent to Callable[..., X] (also Callable[[()], X] is treated as equivalent to Callable[[], X]). PEP 484 does not specify the former forms, so that this PR makes them prohibited.

I do not have any preference on this, so please feel free to either merge or close this.

@gvanrossum
Copy link
Member

Strange that was ever accepted. Was this aways there? I don't recall intending to support this.

@ilevkivskyi
Copy link
Member Author

@gvanrossum It look like it was introduced in #308 when I split __getitem__ in two parts, so that it could be cached. So that this is my fault. This PR adds tests that prohibit this.

if not isinstance(args, list):
raise TypeError("Callable[args, result]: args must be a list."
" Got %.100r." % (args,))
if not isinstance(args, list) or ... in args or () in args:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... It really shouldn't be necessary to check this here. I think the reason may be that you're trying to make the hash key for e.g. Callable[[int, str], float] be the tuple (int, str, float) rather than just nesting the original structure. The exceptions in __getitem_inner__ seem due to this.

Or maybe you're trying to make __parameters__ a single-level tuple? But there are two exceptions for this, one for Callable[..., t] and one for Callable[[], t] (IIUC). I don't think this is really worth it...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gvanrossum Yes, indeed I wanted to flatten __parameters__ to just call super().__getitem__. But you are right, it is not necessary to do this here, but only right before I actually call super().

@@ -1221,9 +1221,9 @@ def __getitem__(self, parameters):
elif args == []:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need this special case, and if you remove it and the matching special case in __getitem_inner__ the tests still passes. (It's different here than for Tuple -- while Tuple[] is invalid due to Python's syntax, Callable[[], t] is fine, and there's no need to treat an empty list special.

PS. I can't add a comment there, but your code below has [...,] and [(),] -- those trailing commas are not needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gvanrossum You are right, only ellipsis needs special case (in two places you mention, and also in __repr__).

@ilevkivskyi
Copy link
Member Author

@gvanrossum Thanks for review! I pushed new commits taking into account your comments. Now this is much simpler (and probably right) way to fix this.

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point in the future we should also add comments explaining the inner workings of all these functions. (Or docstrings, but make it clear they are NOT public or even protected APIs.)

else:
if not isinstance(args, list):
raise TypeError("Callable[args, result]: args must be a list."
" Got %.100r." % (args,))
parameters = tuple(args) + (result,)
parameters = tuple(args), result
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd put (redundant) parentheses around the RHS just to emphasize that we're really creating a two-tuple here.

msg = "Callable[args, result]: result must be a type."
result = _type_check(result, msg)
if args == [...,]:
if args == ...:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd spell this as Ellipsis -- seeing args == ... is just too weird. :-) Plus it's a singleton, so you should use is.

@ilevkivskyi
Copy link
Member Author

@gvanrossum

I implemented your latest comments in a new commit.

At some point in the future we should also add comments explaining the inner workings of all these functions. (Or docstrings, but make it clear they are NOT public or even protected APIs.)

This is a good idea, I will make a PR later this week.

@gvanrossum gvanrossum merged commit cf7ba5d into python:master Nov 7, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants