I have some python (v2.7) code that uses OS X's built in PyObjC bindings to get the executable's path from a bundle via NSBundle bundleWithPath:
#bundlePath is a string/path to a .app or .kext
mainBundle = Foundation.NSBundle.bundleWithPath_(bundlePath)
if mainBundle:
binaryPath = mainBundle.executablePath()
A customer reported that this was throwing an exception, and emailed me the backtrace:
...
File "utils.py", line 184, in getBinaryFromBundle
binaryPath = mainBundle.executablePath()
AttributeError: 'NoneType' object has no attribute 'executablePath'
Unfortunately, I can't replicative this on my box. NSBundle bundleWithPath: always returns either None, or a valid bundle object, which the code seems to handle as expected.
>>> print Foundation.NSBundle.bundleWithPath_(None)
None
>>> print Foundation.NSBundle.bundleWithPath_("invalid/path")
None
>>> print Foundation.NSBundle.bundleWithPath_("/Applications/Calculator.app/")
NSBundle </Applications/Calculator.app> (not yet loaded)
Sure I could wrap this code in a try/except, but my question is, why isn't the if statement preventing this exception?
update 1
Based on suggestions, I've confirmed that:
1) indentation is correct
2) the customer is using the correct (most recent) code
...still trying to figure this one out!
The issue is not that the bundleWithPath
call is returning something unexpected. As you said, None
is a valid return value for it.
This suggests that the client's machine has a strange version of python in which
if None:
print('hello, strange world')
else:
print('hello, world')
would actually print hello strange world
.
I've never seen this myself, but it's the only explanation for what you are seeing, and there are a truckload of different python interpreters, so it's not shocking to me that one of them is a bit odd.
The commonly accepted practice for checking if a variable is None
is to do so explicitly anyway -- it's a whole lot clearer to read, IMHO.
if mainBundle is not None:
...
The whole practice of coercing NoneType
to False
for boolean expressions leads to some weird and unclear semantics, especially when you have code that can produce True
, False
, or None
.
I know this doesn't answer the "why" part of the question, but I'm chalking it up to a strange python version. It's hard to say more without having detailed information about the client's computer, or at least knowing the version of python being run.