Ex46 ModuleNotFoundError

@io_io, I followed the skeleton file for tests (NAME_tests.py) in exercise 46:

from nose.tools import *
import NAME

def setup():
print(“SETUP”)

def teardown():
print(“TEAR DOWN!”)

def test_basic():
print(“I RAN!”, end=’’)

When running NAME_tests.py individually from the command line, the full error message is:

Traceback (most recent call last):
File “NAME_tests.py”, line 2, in
import NAME
ModuleNotFoundError: No module named ‘NAME’

LMK if I should paste more code! It’s verbatim from the book.

Check if you have the latest nose version, google it a bit as far as I know it’s deprecated.
I’d move on to pytest and skip nose testing. Check how tests should be written in pytest.
When I did the exercise I didn’t have any problem, it just worked.

You need to make sure have a file named NAME.py in your current directory. Once you’re sure that’s there the you might have to force python to load it. What OS are you on?

@zedshaw I don’t have a file named NAME.py in my current directory, only a directory that contains an init .py file. My directory structure is:

  • skeleton/
    • NAME/
      • init .py
    • bin/
    • docs/
    • setup.py
    • tests/
      • NAME_tests.py
      • init .py

I call nosetests in the skeleton directory using OS 10.14.5. The ModuleNotFoundError occurs when I change directories to tests and try to run NAME_tests.py. I hadn’t done this step previously, but noticed the issue in exercise 48 when trying to get the import to work for lexicon_tests.py in exercise 48.

You need NAME.py too in the NAME Directory. Your test file tries to import a module called NAME but it doesn’t exist.

Think of the package having folders and files within. The init helps python know it’s a package (and you can do stuff with the init when you get more advanced).

So if your tests try to import NAME, it’s actually the module/file (NAME.py) it’s looking for.

@zedshaw + @gpkesley thanks for the advice! I added NAME.py to the NAME directory, so now the structure looks like:

  • skeleton
    • NAME/
      • _ init _.py
      • NAME.py
    • bin/
    • docs/
    • setup.py
    • tests
      • NAME_tests.py
      • _ init _.py

I cleared out the pycache files and am still having the same error though. Any thoughts? Is there something else I should be adding to the new NAME.py file?

Have you double-checked your setup.py includes the NAME module under packages too?

setup(
...
packages=[‘NAME’],
...

So the setup basically say here is the set up for this programme. It called, blah, blah, blah, by someone, and for it to work, you need the ‘NAME’ module which is part of this package.

@gpkesley I have! My setup.py looks like this as per LPTHW:

try:
from setuptools import setup
except ImportError:
from distutils.core import setup

config = {
‘description’: ‘My Project’,
‘author’: ‘My Name’,
‘url’: ‘URL to project’,
‘download_url’: ‘URL to download project’,
‘author_email’: ‘My email’,
‘version’: ‘0.1’,
‘install_requires’: [‘nose’],
‘packages’: [‘NAME’],
‘scripts’: [],
‘name’: ‘projectname’
}

setup(**config)

I’m going to bet you wrote:

_init_.py – underscore init underscore dot py

But it should be:

__init__.py – underscore underscore init underscore underscore dot py

In fact, I bet if you did that there you my have done it all over. The place you added the NAME.py file would require you to do this:

import NAME from NAME

So that’s probably not what you wanted. I also see you have this single underscore in tests as well. Check it. It could be just the formatting on here though.

@zedshaw I do have underscore underscore init underscore underscore dot py for all my init files in my local drive. The first time I quoted my directory structure in this forum, I believe that the double underscore acted like markup and automatically bolded init, removing said underscores, so I added a blank space and single underscore for clarification in my second comment.

tl;dr My filenames are formatted correctly, I just messed it up in commenting. Still stumped.

Have you tried an absolute path?
from .NAME import NAME
I googled and found this answer, but don’t know if you tried it:

Alright then at this point you’re going to have to make a video for us since there’s nothing else that could be wrong. If you have all the files, you’re inside skeleton and not above it, you have the correct underscores, you’ve set PYTHONPATH, then we can’t figure it out without screenshots of the fail or a video. A screenshot would work but you’d have to do:

  1. pwd and ls where you are
  2. the export PYTHONPATH
  3. The nosetest run and result.

Other mistake people make is they cd tests to try to run them. Once you do that python thinks this is the project root and tries to import files from there, so it expects tests/NAME.py to exist. Never cd down into lower directories to run things. You always stay in the project root.

If you don’t have a quick and easy recorder and you are using chrome :face_with_raised_eyebrow: the try https://chrome.google.com/webstore/detail/screen-recorder/hniebljpgcogalllopnjokppmgbhaden?hl=en

@zedshaw I finally figured this out thanks to your last bit of advice! I was cd’ing down into lower directories to run them, rather than staying in the project root. Everything works fine now, thanks!

1 Like

Thanks for sharing the solution.

Yep, the general rule is this:

Never ever CD down into a project directory. All of the modules expect your python interpreter to be located in the root (top) of the project, when you CD down into the lower directories it throws off where modules are. So, imagine you have this project:

mycode/
    bin/app.py
    code/stuff.py

Now imagine that bin/app.py has this inside it:

from code.stuff import TheThing

That import maps like this:

  • code -> code/
  • code.stuff -> code/stuff.py
  • TheThing -> code/stuff.py:class The Thing

So if you were to do a full path of python and map that to a full path on the disk it’d be:

code.stuff.TheThing ===> code/stuff.py:TheThing

That : after .py is a way of saying “Wherever TheThing is defined inside stuff.py” similar to if I wrote “code/stuff.py:42” to get line 42 of code/stuff.py.

Now, imagine if you do this:

cd bin/
python app.py

Your first line tries to load TheThing from the module code.stuff, which then causes python to do this:

  1. look in the current directory for a code/ or code.py file.
  2. Current directory is…bin/ OopS! code/ is one directory up, so this module can’t be found.

The solution is to do this:

$ cd bin/
$ python app.py
# !!ERRORRRRRRRRRRR
# oops I'm in the wrong directory
$ cd ..
$ python bin/app.py
# Ahhhhhh now we're home.

Having same problem as OP, can’t fix it.

I am not CD’ing into a lower directory (e.g. “\ProjectName\tests”).

Name of project is DumbProject. There’s a module (dumb.py) in the appropriate directory along with the required “init.py” file.

Here is my dumb_tests.py (likewise in the appropriate folder with an empty “init.py” file):

from nose.tools import *
import dumb

def setup():
    print "SETUP!"

def teardown():
    print "TEAR DOWN!"

def test_meat():
    print "Doll steak!"

Of course, if I try to run this Python complains it can’t find the module “dumb.”

The instructions in the video / book don’t work as they’re only for Mac or Linux. I’m working on a Windows 10 system. Please help, I’m totally lost.

Just in case it’s some kind of odd path problem, here also is the result of a full ls -r command (I have the Windows Subsystem for Linux installed):

PS C:\Users\WinTenProBox\Google Drive\Python\test_directory\projects\DumbProject> ls -r                                 

    Directory: C:\Users\WinTenProBox\Google Drive\Python\test_directory\projects\DumbProject


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2020-05-28     11:06                bin
d-----       2020-05-22     09:25                docs
d-----       2020-05-28     14:13                dumb
d-----       2020-05-28     14:13                tests
-a----       2020-05-28     12:56            495 setup.py


    Directory: C:\Users\WinTenProBox\Google Drive\Python\test_directory\projects\DumbProject\bin


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2020-05-28     11:10            254 frobnicate.py


    Directory: C:\Users\WinTenProBox\Google Drive\Python\test_directory\projects\DumbProject\dumb


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2020-05-28     06:43            204 dumb.py
-a----       2020-05-22     09:30              0 __init__.py


    Directory: C:\Users\WinTenProBox\Google Drive\Python\test_directory\projects\DumbProject\tests


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2020-05-28     14:13            163 dumb_tests.py
-a----       2020-05-22     09:30              0 __init__.py

Python path seems to be one of the biggest issues that people face when starting out, and when using Nose (which is ivortually deprecated) the whole issue seems more so.

You can check that the module is in the path by adding the directory and checking the path afterwards.

Alternatively, bin Nosetest for unittest or better still, Pytest.

I know @zedshaw considers this book complete/done/finalised, but I do wonder if this section needs to be overhauled in light of the number of issues people have with Nose?

(@zedshaw I’m happy to have a go if it helps…)

1 Like

For now I’d like to stick with the book as-written. I’ll tackle unittest, Pytest, and whatever else is new and different, later.

So how do I fix this?

I made an addition to the code I posted above. I had “dumb_tests.py” print what it thinks the “path” is before attempting to import module “dumb.” To wit:

from os import sys
from nose.tools import *
print sys.path

When I run this revised version of “dumb_tests.py”, it looks like this:

PS C:\Users\WinTenProBox\Google Drive\Python\test_directory\projects\DumbProject> python .\tests\dumb_tests.py
['C:\\Users\\WinTenProBox\\Google Drive\\Python\\test_directory\\projects\\DumbProject\\tests', 'C:\\Windows\\SYSTEM32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 'C:\\Python27\\lib\\lib-tk', 'C:\\Python27', 'C:\\Users\\WinTenProBox\\AppData\\Roaming\\Python\\Python27\\site-packages', 'C:\\Python27\\lib\\site-packages']
Traceback (most recent call last):
  File ".\tests\dumb_tests.py", line 5, in <module>
    import dumb
ImportError: No module named dumb

For some reason Python has the \tests subdirectory of my project in sys.path, but not the \dumb subdirectory. I guess that’s where the problem lies.

I think I found at least a temporary fix. If I add the following to “dumb_tests.py” before attempting to import module “dumb”:

sys.path.append("./dumb")

then “dumb_tests.py” completes successfully. Not sure whether this is the “textbook” answer but it seems to work.

I am having other difficulties with “setup.py” - it thinks one of my /bin scripts isn’t there. Another path problem I expect.

A free service run by Zed A. Shaw for learncodethehardway.org.