[Python-Dev] os.path.join failure mode
Terry Reedy
tjreedy at udel.edu
Sat Feb 9 19:57:41 CET 2013
On 2/9/2013 8:31 AM, R. David Murray wrote:
> On Sat, 09 Feb 2013 09:59:13 +0000, Thomas Scrace <tom at scrace.org> wrote:
>> If a function (or other non-string object) is accidentally passed as an
>> argument to os.path.join() the result is an AttributeError:
>>
>>
>> In [3]: os.path.join(fn, "path")
>>> ---------------------------------------------------------------------------
>>> AttributeError Traceback (most recent call last)
>>> /home/tom/<ipython-input-3-44b097ceab04> in <module>()
>>> ----> 1 os.path.join(fn, "path")
>>> /usr/lib/python2.7/posixpath.pyc in join(a, *p)
>>> 66 if b.startswith('/'):
>>> 67 path = b
>>> ---> 68 elif path == '' or path.endswith('/'):
>>> 69 path += b
>>> 70 else:
>>> AttributeError: 'function' object has no attribute 'endswith'
>>
>> It's relatively easy to run into this if you mean to pass the return value
>> of a function (fn()) as the argument but accidentally forget to append
>> parens (()) to the callable, thus passing the function itself instead.
>>
>> Would it not be more helpful to raise a TypeError("Argument must be a
>> string") than the slightly more mysterious AttributeError?
>>
>> It's not the most difficult error in the world to figure out, I admit, but
>> a TypeError just seems like the more correct thing to do here.
I agree. Since the exception type is not documented and since no one
should intentionally pass anything but strings, and therefore should not
be writing
try:
os.path.join(a,b)
except AttributeError:
barf()
I think it would be acceptable to make a change in 3.4.
> We don't generally do that kind of type checking in Python. Sometimes the
> error that results is obscure enough that adding an early check of some
> sort is worth it, but this one is very clear, so I don't see that an
> additional check would add much value here.
Changing AttributeError to TypeError only requires try-except, which is
cheap if there is no error, not an early type check.
> The reason we avoid such type checks is that we prefer to operate via
> "duck typing", which means that if an object behaves like the expected
> input, it is accepted.
And catching the existing AttributeError allows work-alikes. I agree
that an isinstance check is bad as well as unnecessary.
As it is, the core code for path, given above, is *already* wrapped in
try: except TypeError, (to give a more friendly error message!, as
TypeError is most like from a unicode-bytes mixing). So there would be
no extra cost for correct calls and all that is needed is another except
clause.
except AttributeError as e:
bad = e.args[0].split()[0]
msg = "all components must be strings; one is a {}".format(bad)
raise TypeError("all components must be strings")
Thomas, unless David or someone else shoots down this idea here, I say
go ahead and open an enhancement issue and add terry.reedy as nosy.
--
Terry Jan Reedy
More information about the Python-Dev
mailing list