This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: '' % object() raises TypeError, '' % A() does not
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.2, Python 3.3, Python 2.7
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: amaury.forgeotdarc, cheryl.sabella, loewis, msaghaei, terry.reedy
Priority: normal Keywords:

Created on 2009-07-01 16:14 by msaghaei, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (7)
msg89987 - (view) Author: Mahmoud (msaghaei) Date: 2009-07-01 16:14
When using a class instance as a mapping for the right hand value in a
sting format expression without conversion specifier, it seems logical
that the class has a __getitem__ method. Therefore following format
expression should raise an exception.

>>> class AClass(object):
...   pass
... 
>>> c = AClass()
>>> "a string with no conversion specifier" % c
'a string with no conversion specifier'
msg90000 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2009-07-02 06:00
No, it's not logical that there should be an exception. The result looks
right to me.

You are incorrectly assuming that it would always invoke __getitem__ in
this case, which is not true:

py> "a string with a single placeholder: %s" % c
'a string with a single placeholder: <__main__.AClass object at 0xb7d3b1ec>'

So whether it requires c to be a dictionary depends on whether there are
any %(foo)s conversions in the string. With no conversion specifiers,
the values passed to % are irrelevant.
msg90008 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2009-07-02 11:43
If A is a simple class (old or new style):
   class A: pass

Why is there a difference between:
   "" % object()
and
   "" % A()
?
msg90009 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2009-07-02 12:23
IMO, the *_FromFormat functions are wrong to decide whether the args
object is a mapping. the code is:
    if (Py_TYPE(args)->tp_as_mapping && !PyTuple_Check(args) &&
        !PyObject_TypeCheck(args, &PyBaseString_Type))
        dict = args;

But heap types always fill tp_as_mapping: it points to
PyHeapTypeObject.as_mapping, whose members may be NULL...
PyMapping_Check() would be more appropriate.
msg139221 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2011-06-26 21:00
The original bug claim is invalid. But the following (3.2.0, winxp) strike me as a bug, hence the title change

>>> class A: pass

>>> '' % A()
''
>>> '' % object()
...
TypeError: not all arguments converted during string formatting

More difference:

>>> '%(a)s' % object()
...
TypeError: format requires a mapping
>>> '%(a)s' % A()
...
TypeError: 'A' object is not subscriptable
msg301309 - (view) Author: Cheryl Sabella (cheryl.sabella) * (Python committer) Date: 2017-09-05 13:19
Under 3.7, the examples Terry gave now have consistent results.

>>> '' % A()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting

>>> '' % object()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting

>>> '%(a)s' % object()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: format requires a mapping

>>> '%(a)s' % A()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: format requires a mapping
msg301336 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2017-09-05 17:12
The issue History suggests that the original report was marked for 2.6, 3.0, 3.1.  It is not clear which versions the OP or anyone else tested.  I removed the versions above and added 3.2, 3.3 after reporting a test on 3.2.0.  I did not report 2.7 behavior and don't know when 2.7 was added.

In any case, 2.7.13 has the same % behavior as 3.6 (and 3.7):

>>> '' % 1
...
TypeError: not all arguments converted during string formatting

So someone or ones decided to resolve the inconsistency in a manner the opposite of what Martin suggested.

''.format(1, 2, 3) *does* ignore the extra arguments, but I will not call the difference between % and .format a bug, as it appears intentional.  With f strings, there is no issue of 'extra arguments

I augmented the title to be clearer that the issue was the inconsistency, which is now gone.  Thanks, Cheryl, for rechecking.
History
Date User Action Args
2022-04-11 14:56:50adminsetgithub: 50645
2017-09-05 17:12:05terry.reedysetstatus: open -> closed
title: '' % object() raises TypeError -> '' % object() raises TypeError, '' % A() does not
messages: + msg301336

components: + Interpreter Core
resolution: out of date
stage: resolved
2017-09-05 13:19:01cheryl.sabellasetnosy: + cheryl.sabella
messages: + msg301309
2014-10-04 21:40:18francismbsettype: behavior
2011-06-26 21:00:07terry.reedysetnosy: + terry.reedy
title: No conversion specifier in the string, no __getitem__ method in the right hand value -> '' % object() raises TypeError
messages: + msg139221

versions: + Python 3.2, Python 3.3, - Python 2.6, Python 3.0, Python 3.1
2009-07-02 12:23:29amaury.forgeotdarcsetstatus: closed -> open
resolution: not a bug -> (no value)
messages: + msg90009
2009-07-02 11:43:33amaury.forgeotdarcsetnosy: + amaury.forgeotdarc
messages: + msg90008
2009-07-02 06:00:43loewissetstatus: open -> closed

nosy: + loewis
messages: + msg90000

resolution: not a bug
2009-07-01 16:14:04msaghaeicreate