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
String interpolation doesn't work with sys.version_info #52660
Comments
String interpolation doesn't work with sys.version_info in Python versions in which sys.version_info is a named tuple. It's a regression in Python 2.7 and 3.1. This problem doesn't concern named tuples created using collections.namedtuple(). This problem might also concern sys.getwindowsversion(), but I don't have access to Windows system, so I can't check it. $ python2.6 -c 'import sys; print("%s.%s.%s-%s-%s" % sys.version_info)'
2.6.5-final-0
$ python2.7 -c 'import sys; print("%s.%s.%s-%s-%s" % sys.version_info)'
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: not enough arguments for format string
$ python3.0 -c 'import sys; print("%s.%s.%s-%s-%s" % sys.version_info)'
3.0.1-final-0
$ python3.1 -c 'import sys; print("%s.%s.%s-%s-%s" % sys.version_info)'
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: not enough arguments for format string |
This affects any type implemented as PyStructSequence. For example, sys.flags has the same behavior. |
I think the right way to handle this is to modify the test: if (Py_TYPE(args)->tp_as_mapping && !PyTuple_Check(args) && to also exclude PyStructSequence's, but since they're all distinct types I don't see how to do that. I don't really think listing all of the PyStructSequence types would be acceptable. This is the test that's trying to figure out if %-formatting should use mapping or tuple expansion. |
I am not sure fixing this quirk of %-formatting is worth the trouble given that one simply use new style {}-formatting: $ python-c 'import sys; print("{}.{}.{}-{}-{}".format(*sys.version_info))'
3.2.0-alpha-0 or a work-around $ python -c 'import sys; print("%s.%s.%s-%s-%s" % tuple(sys.version_info))'
3.2.0-alpha-0 |
Well, the problem is that it's a regression from 2.6. |
The other thing to do would be to convince PyTuple_Check that PyStructSequences are tuples, but that would no doubt come with its own set of regressions. Since this problem is 1) hard to fix and 2) probably of minimal impact, I think the best course is to do nothing. |
Yes, but sys.version_info isn't a namedtuple (which are in fact tuples), it's the (sort-of) C equivalent, which isn't a real tuple. >>> from collections import namedtuple
>>> x = namedtuple('x', 'a b c')
>>> '%s %s %s' % x(1, 2, 3)
'1 2 3'
Hmm, but sys.version_info is a tuple:
>>> isinstance(sys.version_info, tuple)
True I'll have to check if PyTuple_Check returns true or not. Maybe the problem is in the mapping check. I'll investigate more. |
IIRC, there is an open ticket to make structseq inherit from tuple to avoid just this kind of problem. |
Looks like that's bpo-1820. |
On Thu, Apr 29, 2010 at 11:52 AM, Raymond Hettinger
Indeed, see bpo-1820. |
Should this regression block final release of 2.7 or can it be fixed in e.g. 2.7.1? |
Here's a patch. It makes structseq a subclass of tuple and along the way deletes tons of code. Please review. |
This is definitely the right way to do it. I expect that I will have only minor nit-picks as I go through the patch.
#define PyStructSequence_SET_ITEM PyTuple_SET_ITEM
#define PyStructSequence_GET_ITEM PyTuple_GET_ITEM there is no need to repeat the argument lists.
I believe tp_free gets inherited, so structseq tp_new should follow what tuple's tp_new does. I am not 100% sure on the second point, though _PyObject_GC_TRACK may be redundant after PyObject_GC_NewVar.
|
2010/7/7 Alexander Belopolsky <report@bugs.python.org>:
I think the preprocessor requires this. (Anyway it fails without.)
I'm not sure it really matters, since the fields should always be
This is only needed when doing freelist magic in tupleobject.c.
Yeah, that's fine. |
On Wed, Jul 7, 2010 at 4:19 PM, Benjamin Peterson
The following pattern is quite common: tuple = PyTuple_New(size): for (i = 0; i < size; ++i) {
item = create_item(...);
if (item == NULL)
goto fail;
}
...
fail:
Py_DECREF(tuple); I don't think this should be outlawed. |
(New patch addresses review.) |
Looks great. I love the patches where few '+'s are drowning in a sea of '-'s! A gratuitous nitpick (feel free to ignore). In + val = PyStructSequence_GET_ITEM(obj, i);
if (cname == NULL || val == NULL) { The null check for val is now redundant, but won't hurt. |
Applied in r82636. |
I would suggest to document changed behavior of string interpolation with sys.version_info and sys.getwindowsversion() in "What’s New in Python 2.7" page and maybe "What’s New In Python 3.1" page. |
This was a fantastic check-in. Thanks Benjamin. |
A side effect of this change is that it kills the ability to have a PyStructSequence which has a smaller visible size than the total number of items. For example, sys.getwindowsversion used to have 5 items in the sequence and 4 items accessible by name only (for backwards compatibility) -- now it's a 9 item tuple. |
Hmm. I was looking for this precise issue when I was reviewing the code and it appeared right to me. I know, I should have tested instead. This should be easy to fix, though. I'll look into it now. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: