Wednesday, November 29, 2017

a __main__ by any other __name__

$ cat <<EOF > what_is_happening.py
if __name__ == "__main__":
    import what_is_happening
else:
    print("what is happening?")
EOF

$ python what_is_happening.py
what is happening?


Ambiguous entrypoints can create a maze of state in your program.  In case the above example doesn't seem so bad, lets make it worse.


$ cat <<EOF > innocent_bystander.py
import what_is_happening

def func(): raise what_is_happening.TrustFall('catch me!')
EOF
 

$ cat <<EOF > what_is_happening.py
import innocent_bystander

class TrustFall(Exception): pass

if __name__ == "__main__":
    try:
        innocent_bystander.func()
    except TrustFall:
        print("gotcha!")
    except Exception as e:
        print('oops, butterfingers!')
        print('{} is not {}.... what have I done?'.format(
            type(e), TrustFall))
EOF

$ python what_is_happening.py
oops, butterfingers!
<class 'what_is_happening.TrustFall'> is not <class '__main__.TrustFall'>.... what have I done?


What happened?  This is executing the main module twice, a special case of double import.

One solution is to put import guards in all entrypoint scripts:
if __name__ != "__main__":
    raise ImportError('double import of __main__')






No comments:

Post a Comment