Skip to content

Clarify namedtuple member rules #1979

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

yangdanny97
Copy link
Contributor

@yangdanny97 yangdanny97 commented Apr 19, 2025

This PR clarifies the typing spec around named tuple fields and adds a few conformance test cases:

  • fields are not being allowed to begin with underscore (and its interaction with rename)
  • which members are counted/not counted as fields

Analogous restrictions are outlined in the spec for enums, but they are not present in the spec for named tuples.

Since this is adding new rules to the spec, should I open a discussion in the forum about it?

@yangdanny97 yangdanny97 marked this pull request as ready for review April 19, 2025 10:36
@erictraut
Copy link
Collaborator

Yes, please start a thread in the discussion forum. I don't think these changes will be controversial, but we should let the community weigh in.

@yangdanny97
Copy link
Contributor Author

@WSH032
Copy link

WSH032 commented May 18, 2025

Hi, I'm not sure if this is the right place for this discussion—if not, please let me know (and sorry!).

I originally raised this issue in pyright, but I think here might be a more appropriate place to discuss it.

Suppose I do have members that start with "_":

NT5 = namedtuple("NT5", ["abc", "_1"], rename=True)  # OK
NT5(abc="", _1=1)  # OK

How can I provide type annotations for them in a .pyi file?

class NT5(NamedTuple):
    abc: str
    _1: int  # <- HOW ?
  • Can we allow an exemption for field names matching the pattern _{index} (e.g., _1)?

  • Or, could the spec recommend that even if a type checker rejects a field name like _1, it should still provide type analysis for that field:

    from collections import namedtuple
    
    from typing_extensions import TYPE_CHECKING, NamedTuple, assert_type
    
    if not TYPE_CHECKING:
        NT5 = namedtuple("NT5", ["abc", "_1"], rename=True)  # OK
    else:
    
        class NT5(NamedTuple):
            abc: str
            _1: int  # type: ignore
            #        #  ^ suppress false positive
    
    
    nt5 = NT5(abc="", _1=1)  # should be ok
    
    assert_type(nt5[0], str)
    assert_type(nt5[1], int)  # should be ok
    
    assert_type(nt5.abc, str)
    assert_type(nt5._1, int)  # should be ok

    Currently, mypy and pyright behave differently on this point.

@JelleZijlstra
Copy link
Member

I'm with Eric on the linked issue that this doesn't make sense to support. If you use different types on both arms of if TYPE_CHECKING, you'll see things like this happen.

Can we allow an exemption for field names matching the pattern _{index} (e.g., _1)?

No, unless the runtime has that exemption. We should match the runtime behavior.

could the spec recommend that even if a type checker rejects a field name like _1, it should still provide type analysis for that field

Type checkers could do that but I don't think it should be the spec's business to decide how type checkers should proceed once they've detected a type error.

@JelleZijlstra
Copy link
Member

And to give a constructive suggestion for your use case: Maybe just don't use namedtuple? If you require names that start with an underscore, it's not the right tool for the job.

@WSH032
Copy link

WSH032 commented May 18, 2025

Fair enough! Thanks for your quick response! 👍

No, unless the runtime has that exemption

It would be nice if typing.NamedTuple also supported a rename=True option at runtime (I think that's outside the scope of this issue discussion 😂).

And to give a constructive suggestion for your use case: Maybe just don't use namedtuple? If you require names that start with an underscore, it's not the right tool for the job.

I can't control the code on the other end; I can only provide type annotations for it (like in a .pyi file).

The workaround I've come up with for now is:

class NT5(tuple[str, int]):
    abc: str
    _1: int

    __match_args__ = ("abc", "_1")

    def __new__(cls, abc: str, _1: int) -> Self: ...

But this isn't as straightforward as typing.NamedTuple.

Anyway, thanks for your help! 🙏

WSH032 added a commit to pytauri/pytauri that referenced this pull request May 18, 2025
WSH032 added a commit to pytauri/pytauri that referenced this pull request May 19, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants