-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Weird n_fields
attributes, etc.
#6546
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
Comments
If they're there they should probably be added. |
These are instances of structseq (https://github.com/python/cpython/blob/main/Objects/structseq.c), an internal CPython type that is almost but not quite like a namedtuple. It may be worth adding a common base class for them in |
Given this comment at the top of the source code for
|
Treating them as namedtuples is also worth a try. |
The constructor is different from namedtuples though. You have to initialize them with a single tuple. |
Oh, I see. Yes, >>> from os import uname_result
>>> uname_result('a', 'b', 'c', 'd', 'e')
TypeError: structseq() takes at most 2 arguments (5 given)
>>> uname_result(('a', 'b', 'c', 'd', 'e'))
posix.uname_result(sysname='a', nodename='b', release='c', version='d', ma
chine='e') There appears to be an optional second argument, which has to be a So, creating a common base class for them in |
With a custom base class, it would be hard to support type-safe indexing, as type checkers hard-code this behavior for >>> os.uname_result('abcde')
posix.uname_result(sysname='a', nodename='b', release='c', version='d', machine='e')
>>> os.uname_result('abcde')[0]
'a' This would be useful for unpacking: sysname, nodename, release, version, machine = os.uname() |
We could do something like this: from typing import ClassVar, Generic, Sequence, SupportsIndex, Type, TypeVar, overload
_T = TypeVar("_T")
_T_co = TypeVar("_T_co", covariant=True)
class structseq(Sequence[_T_co], Generic[_T_co]):
n_fields: ClassVar[int]
n_unnamed_fields: ClassVar[int]
n_sequence_fields: ClassVar[int]
def __new__(cls: Type[_T], seq: Sequence[_T_co]) -> _T: ...
def __len__(self) -> int: ...
@overload
def __getitem__(self, __i: SupportsIndex) -> _T_co: ...
@overload
def __getitem__(self, __i: slice) -> Sequence[_T_co]: ...
class uname_result(structseq[str]):
sysname: str
nodename: str
release: str
version: str
machine: str
x = uname_result('abcde')
sysname, nodename, release, version, machine = x
y = x.sysname
z = x.n_fields
reveal_type(x) # Revealed type is "__main__.uname_result"
reveal_type(y) # Revealed type is "builtins.str"
reveal_type(z) # Revealed type is "builtins.int"
reveal_type(sysname) # Revealed type is "builtins.str*" Advantages:
Disadvantages:
|
I don't think we can do this anyway. It works if we require it to be |
This doesn't work so nicely when the struct sequence contains different types. Surprisingly, most struct sequences only have one type: |
Yes, precisely. It's a "disadvantage" in that it is not a perfect solution, but it's not a regression vis-à-vis the current situation. |
My above suggestion has the disadvantage that the following would pass mypy, but fail at runtime: from os import uname_result
x = uname_result('abcde')
x.sysname = 'foo' A slightly more cumbersome, but more accurate, definition would be something like the following: from typing import ClassVar, Generic, Sequence, SupportsIndex, Type, TypeVar, overload
_T = TypeVar("_T")
_T_co = TypeVar("_T_co", covariant=True)
class structseq(Sequence[_T_co], Generic[_T_co]):
n_fields: ClassVar[int]
n_unnamed_fields: ClassVar[int]
n_sequence_fields: ClassVar[int]
def __new__(cls: Type[_T], seq: Sequence[_T_co]) -> _T: ...
def __len__(self) -> int: ...
@overload
def __getitem__(self, __i: SupportsIndex) -> _T_co: ...
@overload
def __getitem__(self, __i: slice) -> Sequence[_T_co]: ...
class uname_result(structseq[str]):
@property
def sysname(self): -> str: ...
@property
def nodename(self): -> str: ...
@property
def release(self): -> str: ...
@property
def version(self): -> str: ...
@property
def machine(self): -> str: ... |
There are a bunch of
NamedTuple
-like classes in some of the stranger corners of the stdlib that have the following three attributes:n_fields
n_sequence_fields
n_unnamed_fields
For example:
typeshed/tests/stubtest_allowlists/py3_common.txt
Lines 620 to 631 in 1fdd7e4
@Akuli counts 22 classes that are missing these attributes. Some classes, however, do currently define these attributes in the stub currently.
time._struct_time
defines them as properties (which seems incorrect -- they seem more likeClassVar
s to me):typeshed/stdlib/time.pyi
Lines 35 to 50 in 1fdd7e4
As discussed here, these attributes don't seem particularly useful. I'm also not sure there's much harm in having them in the stubs, but it might be weird to have them popping up in autocompletion suggestions.
In any event, they should probably either all be added to the stubs, or all removed from stubs, and added to the "wontfix" section of the allowlists instead of the "missing from stubs" section of the allowlists.
Thoughts?
The text was updated successfully, but these errors were encountered: