Skip to content

Support additional args to namedtuple() #5215

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 11 commits into from
Aug 3, 2018

Conversation

JelleZijlstra
Copy link
Member

@JelleZijlstra JelleZijlstra commented Jun 14, 2018

By letting typeshed do the work.

Fixes #2124, #2127, #4788.

@@ -1,7 +1,7 @@
[case testNamedTupleUsedAsTuple]
from collections import namedtuple

X = namedtuple('X', ['x', 'y'])
X = namedtuple('X', 'x y')
Copy link
Member Author

Choose a reason for hiding this comment

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

My change ends up requiring list to exist in all of these tests. It was easier to just change the namedtuple call than to add [builtins fixtures/list.pyi] everywhere. I left a few with the list to make sure we test that code path.


[builtins fixtures/bool.pyi]

[case testNamedTupleDefaults-skip]
Copy link
Member Author

Choose a reason for hiding this comment

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

will work on enabling this next (#4788)

@@ -13,14 +13,6 @@ s = b'foo'
from typing import TypeVar
T = TypeVar(u'T')

[case testNamedTupleUnicode]
Copy link
Member Author

Choose a reason for hiding this comment

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

This no longer worked because my stub for namedtuple just has str. Apparently we don't support Text in the test stubs, so I just moved this test case to the pythoneval tests.

@@ -27,3 +27,4 @@ class int:
class str: pass
class bool: pass
class function: pass
class ellipsis: pass
Copy link
Member Author

Choose a reason for hiding this comment

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

This was needed because a few tests that import collections didn't have ... available in their fixtures, and my stub for namedtuple uses it.

@@ -138,10 +138,6 @@ MypyFile:1(
from collections import namedtuple
N = namedtuple('N') # E: Too few arguments for namedtuple()

[case testNamedTupleWithTooManyArguments]
Copy link
Member Author

Choose a reason for hiding this comment

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

This test stopped working because this error is now caught during type checking rather than semanal.

return items, types, num_defaults, ok

def extract_defaults_from_arg(self, call: CallExpr, arg: Expression) -> int:
if not isinstance(arg, (ListExpr, TupleExpr)):
Copy link
Member Author

Choose a reason for hiding this comment

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

Technically the defaults argument can be any iterable, but it doesn't seem particularly useful to support that.

@gvanrossum
Copy link
Member

Did anyone else review this yet? It seems oddly stalled (I wonder what happened around June 13, a number of PRs saw their last activity around that date).

@JelleZijlstra
Copy link
Member Author

No. As far as I can see, it's ready for review.

@ilevkivskyi
Copy link
Member

I can review it later today.

@JelleZijlstra
Copy link
Member Author

JelleZijlstra commented Aug 2, 2018 via email

Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

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

Thanks for the fixes! Here are few comments.

@@ -200,8 +200,14 @@ def analyze_var_ref(self, var: Var, context: Context) -> Type:
def visit_call_expr(self, e: CallExpr, allow_none_return: bool = False) -> Type:
"""Type check a call expression."""
if e.analyzed:
if isinstance(e.analyzed, NamedTupleExpr) and not e.analyzed.is_typed:
# Type check the arguments, but ignore the results.
Copy link
Member

Choose a reason for hiding this comment

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

Could you please add a comment here that generating correct errors in call here depends on the typeshed stub?

info = self.build_namedtuple_typeinfo(name, items, types, {})
if num_defaults > 0:
default_items = {
arg_name: EllipsisExpr()
Copy link
Member

Choose a reason for hiding this comment

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

This is a bit hacky so at least deserves a comment why we use EllipsisExpr() instead of using actual expressions.

If possible, I would just use the actual expressions here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think I can get the actual expressions, but I'm not sure I understand why that would be better. It would make the code more complicated and I don't see much of an advantage.

Copy link
Member

Choose a reason for hiding this comment

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

If this is really complex then it maybe doesn't make sense. In general now that we work on mypyc it is simpler if we keep all real info somewhere in the AST.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh yes, this makes sense in the context of mypyc. It isn't too bad actually, I'll just make the change.

if call.arg_kinds != [ARG_POS, ARG_POS]:
# Typed namedtuple doesn't support additional arguments.
if fullname == 'typing.NamedTuple':
return self.fail_namedtuple_arg("Too many arguments for namedtuple()", call)
Copy link
Member

Choose a reason for hiding this comment

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

I would capitalize namedtuple -> NamedTuple due to the proposed change.

A = namedtuple('A', 'a b')
B = namedtuple('B', 'a b', rename=1)
C = namedtuple('C', 'a b', rename='not a bool') # E: Argument "rename" to "namedtuple" has incompatible type "str"; expected "int"
# This works correctly but also produces "mypy/test-data/unit/lib-stub/collections.pyi:3: note: "namedtuple" defined here"
Copy link
Member

Choose a reason for hiding this comment

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

You can add an [out] section at the end that lists all error verbatim instead of using # E:

typename: str,
field_names: Union[str, Iterable[str]],
*,
# really int but many tests don't have bool available
Copy link
Member

Choose a reason for hiding this comment

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

I think this should read "really bool".

@JelleZijlstra
Copy link
Member Author

Thanks for the review! I will push an update soon.

@JelleZijlstra
Copy link
Member Author

Will fix the CI failure later today.

Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

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

Thanks! One last comment. Could you please also fix the self-check? You can merge it after all tests pass.

if len(defaults) > 0:
default_items = {
# We don't have the actual argument expressions any more, so we
# just use Ellipsis for all defaults.
Copy link
Member

Choose a reason for hiding this comment

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

This comment is now outdated.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, removed.

@JelleZijlstra JelleZijlstra merged commit 223d104 into python:master Aug 3, 2018
@JelleZijlstra JelleZijlstra deleted the ntdefaults branch August 3, 2018 18:16
@gvanrossum
Copy link
Member

So the initial description said "Fixes #2124, #2127, #4788." And only #2124 got auto-closed (auto-close isn't smart enough :-). Should the other two also be closed now?

@JelleZijlstra
Copy link
Member Author

Thanks for catching that! I'll close the other ones too.

@JelleZijlstra
Copy link
Member Author

I suppose I should have written "Fixes #2124. Fixes #2127. Fixes #4788."

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.

3 participants