Tags

I was trying to write a program for sending email and I innocuously  saved this program as email.py only to realize this was a mistake. But a good mistake it was for I learned few things! Here is the basic code I was trying to run-

import smtplib

sender = 'mail@email.com'
receivers = ['mail@anotheremail.com']

message = """From: From Person <mail@email.com>
To: To Person <mail@anotheremail.com>
Subject: SMTP e-mail test

This is a test e-mail message.
"""

try:
smtpObj = smtplib.SMTP('localhost')
smtpObj.sendmail(sender, receivers, message)
print "Successfully sent email"
except :
print " unable to send email"

When I ran this program, it threw following error-

ImportError: No module named utils

Here is what went wrong. I imported smtplib module which in turn imports another module email.utils. When your script imports some module, it searches for that module in some particular order. To accomplish this, Python uses a standard module search path. Here is how Python searches for module-

  1. First it will look for module in the directory in which your script lives.
  2. Then it will look for directories listed in environment variable PYTHONPATH (order is important here).
  3. Finally it will look for module in default module directories hardcoded into the interpreter.

The moment it finds a match, it stop searching. In my case, I expect my script to find email.utils module in c:\python27\lib\email. But it actually started searching from the folder it lives in and it found itself. Naturally, it didn’t find any module named utils there and that is why error was shown.

When I dug deeper, I found a way a to check search path. Try this by running following commands in IDLE-

>>> import sys
>>> sys.path
['', 'C:\\Python27\\Lib\\idlelib', 'C:\\Python27\\lib\\site-packages\\django-1.8.4-py2.7.egg', 'C:\\Windows\\system32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 'C:\\Python27\\lib\\lib-tk', 'C:\\Python27', 'C:\\Python27\\lib\\site-packages']

You can see directories and their order of listing in which Python would search for module. The output will be different depending on where your script lives (because, as mentioned above, the first location to be searched will be the directory where your script lives).

I also posted about this issue on Reddit, Al Sweigart (of Automate the Boring Stuff fame) posted a comment in response to my post. I am posting his comment verbatim: –

You can test this yourself. I created a file foodoo.py that has:

import foodoo
print('running', __name__)

…and it prints out:

running foodoo
running __main__

The first line comes when the module is imported. The second comes when the original script runs.

Of course, you NEVER want to do this in real life. It’s very confusing and produces unreadable code. Rename your file instead.

So, I learn a few things through a simple mistake I made. Isn’t that great?

Advertisements