pythonpython-importpython-moduleshadowing

Importing a library from (or near) a script with the same name raises "AttributeError: module has no attribute" or an ImportError or NameError


I have a script named requests.py that needs to use the third-party requests package. The script either can't import the package, or can't access its functionality.

Why isn't this working, and how do I fix it?

Trying a plain import and then using the functionality results in an AttributeError:

import requests

res = requests.get('http://www.google.ca')
print(res)
Traceback (most recent call last):
  File "/Users/me/dev/rough/requests.py", line 1, in <module>
    import requests
  File "/Users/me/dev/rough/requests.py", line 3, in <module>
    requests.get('http://www.google.ca')
AttributeError: module 'requests' has no attribute 'get'

In more recent versions of Python, the error message instead reads AttributeError: partially initialized module 'requests' has no attribute 'get' (most likely due to a circular import).

Using from-import of a specific name results in an ImportError:

from requests import get

res = get('http://www.google.ca')
print(res)
Traceback (most recent call last):
  File "requests.py", line 1, in <module>
    from requests import get
  File "/Users/me/dev/rough/requests.py", line 1, in <module>
    from requests import get
ImportError: cannot import name 'get'

In more recent versions of Python, the error message instead reads ImportError: cannot import name 'get' from partially initialized module 'requests' (most likely due to a circular import) (/Users/me/dev/rough/requests.py).

Using from-import for a module inside the package results in a different ImportError:

from requests.auth import AuthBase
Traceback (most recent call last):
  File "requests.py", line 1, in <module>
    from requests.auth import AuthBase
  File "/Users/me/dev/rough/requests.py", line 1, in <module>
    from requests.auth import AuthBase
ImportError: No module named 'requests.auth'; 'requests' is not a package

Using a star-import and then using the functionality raises a NameError:

from requests import *

res = get('http://www.google.ca')
print(res)
Traceback (most recent call last):
  File "requests.py", line 1, in <module>
    from requests import *
  File "/Users/me/dev/rough/requests.py", line 3, in <module>
    res = get('http://www.google.ca')
NameError: name 'get' is not defined

From Python 3.13 onwards the error message becomes very clear, from the documentation:

A common mistake is to write a script with the same name as a standard library module. When this results in errors, we now display a more helpful error message:

$ python random.py Traceback (most recent call last):   File
"/home/me/random.py", line 1, in <module>
    import random   File "/home/me/random.py", line 3, in <module>
    print(random.randint(5))
          ^^^^^^^^^^^^^^ AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/me/random.py' since it
has the same name as the standard library module named 'random' and
prevents importing that standard library module)

Similarly, if a script has the same name as a third-party module that it attempts to import and this results in errors, we also display a more helpful error message:

$ python numpy.py Traceback (most recent call last):   File
"/home/me/numpy.py", line 1, in <module>
    import numpy as np   File "/home/me/numpy.py", line 3, in <module>
    np.array([1, 2, 3])
    ^^^^^^^^ AttributeError: module 'numpy' has no attribute 'array' (consider renaming '/home/me/numpy.py' if it has the same name as a
library you intended to import)

For cases where you name your module the same as an existing one on purpose and want to handle that situation, see How can I import from the standard library, when my project has a module with the same name? (How can I control where Python looks for modules?)


Solution

  • This happens because your local module named requests.py shadows the installed requests module you are trying to use. The current directory is prepended to sys.path, so the local name takes precedence over the installed name.

    An extra debugging tip when this comes up is to look at the Traceback carefully, and realize that the name of your script in question is matching the module you are trying to import:

    Notice the name you used in your script:

    File "/Users/me/dev/rough/requests.py", line 1, in <module>
    

    The module you are trying to import: requests

    Rename your module to something else to avoid the name collision.

    Python may generate a requests.pyc file next to your requests.py file (in the __pycache__ directory in Python 3). Remove that as well after your rename, as the interpreter will still reference that file, re-producing the error. However, the pyc file in __pycache__ should not affect your code if the py file has been removed.

    In the example, renaming the file to my_requests.py, removing requests.pyc, and running again successfully prints <Response [200]>.


    Note: This doesn't only happen when naming your file as the module you are trying to import. This can also happen if you name your file the same as a module imported by a module you import directly. For example, having a file called copy.py and trying to import pandas from there, will give

    ImportError: cannot import name 'copy' from 'copy'
    

    That is because pandas imports copy. There is no magic solution here as you can't know all the modules' names in the world, but a rule of thumb is to try to make names of modules as unique as possible and try to change the name whenever you get such error.