Importance of importing, without imploding

2014-04-02 UPDATE: I found a a much better way to solve this problem.

I have spent the better part of a day, and several rounds of digging at Stackoverflow, to figure out the solution to this issue. It was so tricky (for my middle-aged brain at least) that I want to share it with the world in as simple and straightforward a way as possible in the hope I save some fellow newbies some aggravation.

The more I code, and the more problems I solve with code, the more I don’t want to have to solve the same problem more than once. I’ve tasted the elegant efficiency of re-using code. Once I have a piece of code “perfected” I want to put it in a directory that I can access from any of my projects. How can I share code among several projects in different directories? Here’s my example:

I have two project directories and a directory called “tools” that contains a module “coolstuff.py”. All three directories are subdirectories of ‘Projects.’ “coolstuff.py’ contains a function also called “coolstuff.” I want to be able to import and use the “coolstuff” function in either of my project directories.

c:\mypath\projects\ProjectA\spam.py
c:\mypath\projects\ProjectB\eggs.py
c:\mypath\projects\tools\coolstuff.py

Contents of coolstuff.py:

def coolstuff():
    """
    This is a cool function you should use often.
    """
    print ("Cool function activated!")

I want to be able to call “coolstuff()” from either “spam.py” or “eggs.py.” Obviously I need an import statement. I started off with just ‘import coolstuff’, but that didn’t work. I’ll spare you the gory details of what I went through to find this solution, but suffice it to say, it involved just about every version of “from … import ….”, “import….”, etc., so I’ll just skip straight to the answer:

Contents of ‘spam.py’:

import sys
sys.path.append('C:/mypath/projects/tools')
from coolstuff import coolstuff
coolstuff()

The “sys” module allows run-time addition to the “PATH” environmental variable using the ‘sys.path.append’ statement. This allows the ‘import’ statement to find ‘tools’ and whatever is in it.

Since the function I want is ALSO named ‘coolstuff’, I have to reference it to the right of the import statement. When I finally got the path issue solved so that the statement ‘import coolstuff’, by itself, went error free, I got a ‘module object is not callable’ error when I tried to actually use the function. Turns out, of course, that the FILE ‘coolstuff’ is the ‘module object’, and the FUNCTION ‘coolstuff’ inside the FILE ‘coolstuff’ has to be called in order to work, hence: ‘from coolstuff import coolstuff.’

For the time being, I prefer to name my modules with the same name as the functions they contain, so that one glance in the ‘tools’ directory is all I need to find the function I want. I prefer to set the “PATH” variable at runtime so I don’t have to monkey with my PC’s environmental settings manually ever time I move code to a different folder.

Hope this clears things up for anyone who was similarly vexed.