Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

How to troubleshoot ModuleNotFoundError?

+4
−0

I ran some Python code and it crashed with ModuleNotFoundError. What is the general approach for dealing with these situations?

History
Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

0 comment threads

2 answers

+3
−0

Root cause

ModuleNotFoundError is a kind of ImportError. It occurs when Python code tries to use an absolute import, but can't find the named module - just as the name suggests. (Failed relative imports will only raise the base ImportError. This makes sense because an absolute import involves searching for the module, but for a relative import, Python should already know exactly where to look.)

Understanding sys.path

In general, Python looks for absolute imports by searching within folders that are named in the path attribute of the sys standard library module (sys.path). User code can modify or reassign the list like any other list; and reassigning it does affect module lookup.

However, this is rarely necessary and should always be carefully considered. Popular, complex third-party libraries often span tens of thousands, or even hundreds of thousands of lines of code without needing to do this.

At startup, sys.path is initialized according to clearly documented rules. Rather than trying to modify sys.path from within the code before attempting an import, it's normally a better idea to set the PYTHONPATH environment variable.

Normally, when Python is asked to do an absolute import, it will check each folder listed in sys.path - the folder itself only, not searching in any subdirectories - for a .py file with the right name, or some other implementation (e.g. a compiled .pyc bytecode file contained within a __pycache__ subdirectory; in Python 2.x, the .pyc files were expected to be side-by-side with the corresponding .py source code). It's possible to modify this search process, but that's beyond the scope of this answer. Some "built-in" standard library modules, such as sys, bypass this search process; the module is directly created within the Python implementation. (Among other things, this makes it possible to import sys without needing sys.path to exist already.)

(TODO: factor out a separate Q&A for this?)

Troubleshooting

Always check for typos first, of course.

If you didn't write the code to be imported yourself, it's important to understand whether that code is part of the standard library (something that comes with Python) or is third-party (needs to be installed separately). Check the Python standard library documentation to know what is included.

Everything else must be installed separately. Normally, third-party code is installed using Pip (the pip command-line program) - but if you set up the Python environment using Anaconda, you should use its tool (conda) instead. Some packages have custom installation instructions; in these cases you will have to read their documentation first.

When importing from the standard library

If you are trying to import a standard library module, outside of a very few special cases, the module can really only be not found due to a typo. (Of course, other things can indeed go wrong.)

But, for completeness:

TKinter

This is part of the standard library, but in some cases it may not be included with a Python distribution. This especially happens on Linux and MacOS machines, for a copy of Python that came with the operating system. To get TKinter, you may need to use the system package manager (not Pip) to install it. However, it's often better to install a separate Python version. Every Python installer from https://www.python.org should include Tkinter (and configure everything else needed for it on your system) automatically, and the defaults for compiling from source on Linux should include it as well.

(TODO: separate Q&A for details on this problem)

zlib

Similarly, Python may be built in such a way that it doesn't include the zlib standard library module.

OS-specific modules

Certain modules may only be available depending on the operating system, because they are used to provide OS-level functionality. These are listed in the "MS Windows Specific Services" and "Unix Specific Services" sections of the standard library documentation.

Modules removed or renamed in Python 3

Several standard library modules were renamed or reorganized for Python 3. Some old guides may refer to the Python 2 names of standard library modules, or old code may need to use something else in order to update for Python 3.

Here is a comprehensive listing of the changes:
Module removed or renamed Workarounds
_winreg renamed to winreg
ConfigParser renamed to configparser
copy_reg renamed to copyreg
Queue renamed to queue
SocketServer renamed to socketserver
markupbase renamed to _markupbase - n.b. this is not intended for public use; it's an implementation detail for html.parser
repr renamed to reprlib
test.test_support renamed to test.support
Tkinter (and several others) Use tkinter; the module was renamed to conform to standard naming conventions. There used to be many Tkinter "package contents" that were actually top-level modules; now tkinter is a proper package.
anydbm, dbhash, dumbdbm, gdbm, whichdb Use the dbm package. These used to be separate modules (including dbm itself); now dbm is a package including all this functionality.
HTMLParser Use html.parser; see the new html package
htmlentitydefs Use html.entities
urllib2 Use urllib.error and urllib.request; see the urllib package. Python 2 had separate urllib and urllib2 modules; now urllib is a package that includes urllib2 functionality (and more).
urlparse Use urllib.parse
robotparse Use urllib.robotparser
httplib Use http.client; see the http package
BaseHTTPServer, CGIHTTPServer, SimpleHTTPServer Use http.server
Cookie Use http.cookies
cookielib Use http.cookiejar
xmlrpclib Use xmlrpc.client; see the xmlrpc package
DocXMLRPCServer, SimpleXMLRPCServer Use xmlrpc.server
sets Removed; use the built-in set type instead. (This is extremely obscure; this library was added in 2.3, and the built-in set type was added in 2.4.)
new Removed; use types instead. The API is different, so code will need to be changed.

In most cases, the 2to3 tool should be able to fix these imports automatically.

Modules removed in Python 3.12

The What’s New In Python 3.12 document mentions that a few standard library modules are no longer available:

Module removed Workarounds
asynchat Use the new asyncio module instead; the API is different, so code will need to be adapted.
asyncore Use the new asyncio module instead; the API is different, so code will need to be adapted.
distutils Upgrade to use Setuptools instead; but keep in mind that it's encouraged to use pyproject.toml as much as possible for configuration. Running the setup.py script directly is now deprecated; instead, Setuptools will invoke it for you during the building process.
imp Use the new importlib module instead; the API is different, so code will need to be adapted. Some basic guidance is included in the documentation.
smtpd The documentation recommends the third-party aiosmtpd package instead.

Many more old modules will be removed in 3.13, following PEP 594.

When importing from a third-party package

As well as checking for typos, make sure that you know what name to import. If you installed a third-party library from PyPI, the name that should be used with the import statement in your code does not necessarily have anything to do with the name used to find the package on PyPI. The PyPI name doesn't even have to be a valid Python identifier (in particular, it can use - characters).

Here are some commonly encountered mismatches:
PyPI package name Package names to use in code
pillow PIL (from PIL import Image etc.)
python-dateutil dateutil
beautifulsoup4 bs4 (from bs4 import BeautifulSoup)
opencv-python cv2
google-api-python-client googleapiclient
(e.g. from googleapiclient.discovery import build). Some older versions may use apiclient instead.
python-docx
(There is also a docx PyPI package, but it is abandoned and does not support 3.x)
docx
pywin32
(previously pypiwin32 and probably other names)
win32api, win32com etc. (many other top-level packages)
pyserial serial

If the code has the correct name and you have verified that the package has been installed (for example by using pip list, pip show with the PyPI package name, or trying to install again and getting a Requirement already satisfied message), this happens because the script is using a different Python environment rather than the one where the package was installed. (TODO: separate Q&A for this issue)

When importing your own code

If you have code from other projects that you wrote yourself and need to use in the current project, generally it will be better to make an installable package and install it locally - even if you don't want to distribute it on PyPI (yet?).

Failing that, however, you will need to make sure that sys.path includes the appropriate path for the other code.

If, on the other hand, you are trying to import code that is part of the same project, this should mostly be done using relative imports instead.

The recommended way to organize a Python project is to have most of the code inside a package folder (or sub-folders), perhaps with some simple "driver" scripts just outside. In normal cases, the search path will include the folder with the "driver" scripts, so they can easily do an absolute import of some specific module inside the package. Then, within the package, use exclusively relative imports to connect different parts of the project. This minimizes the dependence on the module search path and helps prepare for packaging the code properly for distribution.

That said, absolute imports usually don't cause a ModuleNotFoundError, because the default sys.path (see the previous section on sys.path) should make it possible to find the other code. The most common problem occurs when trying to use the code in interactive mode (from the Python interpreter prompt). In this case, sys.path will normally include a '' entry, which is a relative path to the current working directory. As a result, using code like os.chdir can prevent modules from being found in the expected place.

History
Why does this post require moderator attention?
You might want to add some details to your flag.

0 comment threads

+2
−0

ModuleNotFoundError means that in running your program, Python attempted to import some module xyz but it was not present on your system.

It could be that you forgot to install the module (forgot to pip install -r requirements.txt), misspelled the module name, or tried to import a module that doesn't exist. But that would be somewhat obvious, so let's assume it's not that, and the module name is correct. However, do note that some packages on PyPI for example have surprising import names - sometimes you pip install xyz but import pyxyz etc - this should normally be covered in the package's documentation.

The first useful thing is to find a way to test the import easily. If you got ModuleNotFoundError: No module named 'xyz', you can reproduce it by running python -c 'import xyz' in your shell: If the import succeeds, it will print nothing and exit with code 0. If the import fails, you will see the ModuleNotFoundError again.

Often, package imports fail due to an environment mismatch. The package is actually installed, but in another Python venv, and not in the current one. It's of course hard to find putative "other" venvs on your computer, but you can look in obvious places like a venv/ dir in the project directory. pip list will show the packages installed in the current environment, so that can help identify them. You can of course just install them again in the current environment as an alternative to looking for the other one.

The environment stuff often comes up due to using "helper" programs, like conda or pyenv. IDEs with integrated Python consoles, like VS Code's Python tab, can also start it with a different environment than your terminal. It's useful to be mindful of which helper programs you are using and how they handle environments, and avoid helpers that are hard to understand.

As a brute force solution, you can try searching for the package or module xyz on your computer: rg xyz / (rg is https://github.com/BurntSushi/ripgrep). Because of Python's import system and conventions, if there is an importable xyz, there is probably a file xyz.py somewhere. You can analyze its path to figure out what environment it is.

History
Why does this post require moderator attention?
You might want to add some details to your flag.

0 comment threads

Sign up to answer this question »