classification
Title: Refactor typing.NamedTuple
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.9
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: gvanrossum, levkivskyi, serhiy.storchaka, xtreak
Priority: normal Keywords: patch

Created on 2020-04-04 21:08 by serhiy.storchaka, last changed 2020-08-10 09:37 by serhiy.storchaka. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 19371 merged serhiy.storchaka, 2020-04-04 21:12
Messages (5)
msg365783 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-04 21:08
typing.NamedTuple is used in two ways.

1. It is a callable which produces a new namedtuple type.
2. It can also be used as a base in the class statement for creating a new namedtuple type.

In both cases it is not a real class. You cannot create an instance of NamedTuple or a subclass of NamedTuple. But it is implemented as a class, and help() shows methods and data descriptors for it, which are useless.

The proposed PR implements NamedTuple like a function. Implementation of the __mro_entries__ method allows to use it as a base in the class statement.
msg365788 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-04 21:21
See also issue40187.
msg365972 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-04-08 07:59
New changeset a2ec06938f46683e33692615aca3875d8b8e110c by Serhiy Storchaka in branch 'master':
bpo-40185: Refactor typing.NamedTuple (GH-19371)
https://github.com/python/cpython/commit/a2ec06938f46683e33692615aca3875d8b8e110c
msg375101 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2020-08-10 08:38
This seems to have caused a test failure in astroid project. I am not sure if the fix needs to be done from their end probably relying on some implementation detail or from the patch itself. Feel free to ignore if it's a third-party only error.

Reproducer script : /tmp/namedtuple_astroid.py

from astroid import parse

mod = parse('''from typing import NamedTuple; NamedTuple("A")''')
print(str(next(mod.body[-1].value.infer())))
assert str(next(mod.body[-1].value.infer())) != 'Uninferable'

Before this commit : 

python /tmp/namedtuple_astroid.py
Instance of typing.NamedTuple

After this commit : 

python /tmp/namedtuple_astroid.py
Uninferable
Traceback (most recent call last):
  File "/tmp/namedtuple_astroid.py", line 4, in <module>
    assert str(next(mod.body[-1].value.infer())) != 'Uninferable'
AssertionError
msg375105 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-08-10 09:37
$ echo 'from typing import NamedTuple; NamedTuple("A")' | ./python -m ast
Module(
   body=[
      ImportFrom(
         module='typing',
         names=[
            alias(name='NamedTuple')],
         level=0),
      Expr(
         value=Call(
            func=Name(id='NamedTuple', ctx=Load()),
            args=[
               Constant(value='A')],
            keywords=[]))],
   type_ignores=[])

So mod.body[-1].value is a call:

    Call(func=Name(id='NamedTuple', ctx=Load()), args=[Constant(value='A')], keywords=[])

I do not know what Astroid does with this node, but seem the problem is in its infer() method.
History
Date User Action Args
2020-08-10 09:37:33serhiy.storchakasetmessages: + msg375105
2020-08-10 08:38:14xtreaksetnosy: + xtreak
messages: + msg375101
2020-04-08 08:05:31serhiy.storchakasetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2020-04-08 07:59:20serhiy.storchakasetmessages: + msg365972
2020-04-04 21:21:34serhiy.storchakasetmessages: + msg365788
2020-04-04 21:12:52serhiy.storchakasetkeywords: + patch
stage: patch review
pull_requests: + pull_request18733
2020-04-04 21:08:45serhiy.storchakacreate