Skip to content

uname_result _asdict and _fields are missing platform #97966

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

Closed
jaraco opened this issue Oct 6, 2022 · 6 comments
Closed

uname_result _asdict and _fields are missing platform #97966

jaraco opened this issue Oct 6, 2022 · 6 comments
Assignees
Labels
type-bug An unexpected behavior, bug, or error

Comments

@jaraco
Copy link
Member

jaraco commented Oct 6, 2022

Not sure if this should be a new issue, but platform.uname docs for 3.12 still say:

... Returns a namedtuple() containing six attributes: system, node, release, version, machine, and processor.

(my emphasis)

I've got python 3.10.6 installed, which returns 5 attributes, not including processor, as expected from the discussion above:

uname_result(
    system='Linux', 
    node='MyName', 
    release='5.15.0-48-generic', 
    version='#54-Ubuntu SMP Fri Aug 26 13:26:29 UTC 2022', 
    machine='x86_64'
)

Originally posted by @dennisvang in #84750 (comment)

Linked PRs

@jaraco jaraco self-assigned this Oct 6, 2022
@jaraco
Copy link
Member Author

jaraco commented Oct 6, 2022

I guess it's not as simple as you describe, because the code does attempt to emulate a 6-item tuple:

>>> import platform
>>> res = platform.uname()
>>> len(res)
6
>>> res[5]
'arm'

It's only in the repr that the platform isn't presented.

All six attributes are present.

I can tweak the docs to make this clearer, but is there an issue you encountered as a result?

@dennisvang
Copy link

dennisvang commented Oct 7, 2022

It's only in the repr that the platform isn't presented.

All six attributes are present.

I can tweak the docs to make this clearer, but is there an issue you encountered as a result?

@jaraco Thanks for converting my comment to an issue,

You're right, len(platform.uname()) is indeed 6.

To be more precise, my issue actually arises from the use of _fields and _asdict() on the return value (uname_result):

Python 3.10.6 (main, Aug 10 2022, 11:40:04) [GCC 11.3.0] on linux
>>> import platform
>>> len(platform.uname()._fields)
5
>>> len(platform.uname()._asdict())
5

My code was expecting a length of 6 (and a processor field).

@kwsp
Copy link
Contributor

kwsp commented Oct 10, 2022

The documentation said the return type is a namedtuple, but in reality the returned type uname_result is a hacked namedtuple that prevents unnecessary computation of the platform property. It tries to emulate a namedtuple, but doesn't support all documented methods on a namedtuple.

I think the way to fix this is to either edit the documentation of platform.uname() to specify these caveats, or completely emulate all documented methods of a namedtuple on the uname_result. The second option seems hard to maintain, and is prone to bugs in the future, so I vote editing the documentation of platform.uname()

@jaraco
Copy link
Member Author

jaraco commented Oct 16, 2022

I agree. Specifying the caveats is probably better.

Another option might be to deprecate the (named)tuple behaviors altogether, which I proposed in #84758, but which was rejected.

If we follow the guidance from @malemburg in that issue, it would suggest to fully emulate the namedtuple for unrelenting backward compatibility. Probably the implementation should support _fields and _asdict for compatibility with old versions.

@jaraco jaraco added the type-bug An unexpected behavior, bug, or error label Oct 16, 2022
jaraco added a commit to jaraco/cpython that referenced this issue Oct 16, 2022
…e platform attribute and to indicate when it became late-bound.
@jaraco jaraco changed the title uname docs mismatch with behavior on number of attributes uname_result _as_dict and _fields are missing platform Oct 16, 2022
@jaraco jaraco changed the title uname_result _as_dict and _fields are missing platform uname_result _asdict and _fields are missing platform Oct 16, 2022
jaraco added a commit to jaraco/cpython that referenced this issue Oct 16, 2022
jaraco added a commit to jaraco/cpython that referenced this issue Oct 16, 2022
@kwsp
Copy link
Contributor

kwsp commented Oct 17, 2022

Re emulating namedtuple's behavior: we go through all this trouble just to avoid computing platform when we call uname? I looked at git blame and traced this back to https://bugs.python.org/issue35967, but I still don't understand the significance of a late bound computation of platform. Since we can cache that property so all subsequent calls to uname are free, how bad would it be if we just compute platform on the first call to uname?

@jaraco
Copy link
Member Author

jaraco commented Oct 17, 2022

The problem is a race condition / circular dependency on Linux/Mac:

  • A project (e.g. cmdix) wishes to implement the uname command in Python.
  • When that package is installed for testing, it exposes uname on the path.
  • When running tests, another library, pkg_resources calls platform.uname() to check installed packages and evaluate environment markers (though it doesn't use the processor attribute).
  • platform.uname() will create a subprocess to the uname -p command to get the processor eagerly.
  • Because uname is now implemented by the project, it is invoked for the subprocess, and its own entry point will import pkg_resources and thus invoke platform.uname(), recursing to the prior step.

Furthermore, this infinite loop is implemented in a subprocess loop, so it's not caught by the max recursion depth, so will consume resources on the user's machine until it runs out of some resource (memory, file descriptors, ...).

All of this happens before cmdix code is ever reached (even the script handler is written by setuptools), so there's nothing cmdix can do to bypass the undesirable behavior.

You can reproduce this behavior by checking out cmdix and attempting to run the tests on Python 3.8 or earlier. Just run tox -e py38 on Linux or Mac in a checkout of the project. It will appear to hang while it creates a giant tree of recursive subprocess calls.

Other ways I've considered to address the issue include:

  • Don't use subprocess to resolve the processor, but instead invoke APIs directly. Unfortunately, the APIs that uname -p uses are subtle and vary across platforms and distributions. Maintaining compatibility without shelling out to uname -p would be difficult if not intractable.
  • pkg_resources could write its own port of uname that doesn't shell out to any processes. This approach would fix the proximate cause but not the root cause, and the root cause could potentially get triggered by another code path, suggesting that no library should use platform.uname if they can't guarantee that uname -p is safe to call.

jaraco added a commit that referenced this issue Oct 30, 2022
…form attribute and to indicate when it became late-bound. (#97972)
jaraco added a commit that referenced this issue Nov 26, 2022
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Nov 26, 2022
…nd ._asdict would include the processor. (pythongh-98343)

(cherry picked from commit dc063a2)

Co-authored-by: Jason R. Coombs <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Nov 26, 2022
…nd ._asdict would include the processor. (pythongh-98343)

(cherry picked from commit dc063a2)

Co-authored-by: Jason R. Coombs <[email protected]>
miss-islington added a commit that referenced this issue Nov 26, 2022
…sdict would include the processor. (gh-98343)

(cherry picked from commit dc063a2)

Co-authored-by: Jason R. Coombs <[email protected]>
miss-islington added a commit that referenced this issue Nov 26, 2022
…sdict would include the processor. (gh-98343)

(cherry picked from commit dc063a2)

Co-authored-by: Jason R. Coombs <[email protected]>
@jaraco jaraco closed this as completed Feb 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants