A Little Gotcha with Naming Python Files

“TypeError: ‘module’ object is not callable”

Brian Terczynski
2 min readDec 20, 2022

I was writing a simple little Python script to recursively print out file names with a certain extension. I was using glob to do this:

import glob
import sys

files = glob.glob(sys.argv[1] + '/**/*.png', recursive=True)
for f in files:
print(f)

For lack of a better name, I called it glob.py . When I ran it I got:

Traceback (most recent call last):
File "/home/brian/glob.py", line 1, in <module>
import glob
File "/home/brian/glob.py", line 4, in <module>
files = glob.glob(sys.argv[1] + '/**/*.png', recursive=True)
TypeError: 'module' object is not callable

I had no idea what this meant.

Of course I used good ole’ Stack Overflow to figure out what might be going on. There were several answers in that article, but this answer described the problem I was having: the name of my Python file was the same as the glob module I was trying to import. So when theimport glob statement was reached my script was inadvertently importing itself, rather than the actual glob module I wanted to import. And thus the error.

Simple solution: rename my file to something else.

But what if I wanted to keep my file name?

I tried a few things:

The PYTHONPATH environment variable.

According to python3 --help , you can set the PYTHONPATH environment variable, which is supposed to prepend its entries to the sys.path variable, which is the search path for loading Python modules (as described here). However, it seems that according to that same documentation, the directory of the script being run comes before PYTHONPATH, and in fact that is what I observed when I printed out the value of sys.path . So in my case where I needed to deprioritize loading from the directory of my input script, this technique did not work.

Modify sys.path

I was reading that you could actually modify sys.path yourself. So I tried doing that before importing glob:

sys.path = ['/usr/local/python3.10'] + sys.path
import glob

(To do this, I had to find the location of the glob module, which according to this I could get by calling glob.__file__.) Unfortunately that also did not work, even though when I printed out the modified value of sys.path , it did have /usr/local/python3.10 listed first. So I’m not sure why that didn’t work.

Use SourceFileLoader

This article listed a few other techniques to have more control over how modules are imported. One suggestion was to use SourceFileLoader:

from importlib.machinery import SourceFileLoader
glob = SourceFileLoader("glob", "/usr/lib/python3.10/glob.py").load_module()

This worked for me.

Conclusions

  • Try not to name your Python file with the same name as another module you are trying to import.
  • If you must, then you will need to try to do some manipulation of the module import path, although it may be hard (or perhaps not possible) to get Python to not search the input Python script’s directory first.
  • So try using SourceFileLoader instead (or one of the other techniques listed in this article).

--

--

Brian Terczynski

Documenting my learnings on my journey as a software engineer.