Running Nosetest on Ex47?

Thank you very much ! I was really stuck here and you fixed it for me. You were very helpful!!!
Im almost done this one and on to ex48 :slight_smile:
Best regards ,
Rick

1 Like

Also, sometimes you have to force the PYTHONPATH to the local directory. On Linux/OSX it’s like this:

export PYTHONPATH=.

On windows this doesn’t come up as a problem that often, but let me know if you need that line too.

I had no end of trouble. I could not get the three tests to work in Ex47. The problem was simple in the end and I found it while watching your video. At one stage I saw the game.py file in the Ex47 directory, that’s what it says right? It kept failing over and over (I kept getting ran 0 tests) and I typed in all the code a few times. Then while watching the video I saw your location for game.py was ex47/ex47/game.py
No problems now. I thought changing the master directory to something else would maybe ease the problem.

1 Like

Hmmm, yes I think I cover it but whenever you code python you stay above your code. So let’s say you have a file like:

ex47/game.py

The mistake people make is they do this:

cd ex47
nosetests

That fails because all of your code talks about ex47 being a module. Like this:

from ex47 import game

That means your code thinks you’re above game.py, hanging out so you can see ex47. So to solve it, do this:

cd …
ls

If you don’t see ex47/ then you’re not in the right place. Then do this:

ls ex47/game.py

If you can’t do that you aren’t in the right place. Once you can then you’re ready to go.

Thanks for the reply Zed.

It was a silly error, easy to make. Just thought if anyone else was struggling it might help.

I’m curious, why does my nosetest succeed running from the top-level directory, but the test code fails when run from tests/? ls ex47/game.py works.

Directory structure:
ex47

  • bin/
  • docs/
  • ex47/
    • _init_.py
    • game.py
  • setup.py
  • tests/
    • _init_.py
    • ex47_tests.py

Import statement in ex47_tests.py:
from ex47.game import Room

when running python ex47_tests.py from tests/:

Traceback (most recent call last):
  File "ex47_tests.py", line 2, in <module>
    from ex47.game import Room
ModuleNotFoundError: No module named 'ex47'

It looks like you might not understand how modules relate to files. When I do this in python:

from ex47 import game

Python starts in my PYTHONPATH (do echo $PYTHONPATH on Linux/OSX) and searches for a file that is:

ex47/game.py

Now, let’s say you cd down into tests/ but your PYTHONPATH only has . in it because you did:

export PYTHONPATH=.

Well, python will look for these files from the tests/ directroy, so it’s kind of looking for:

tests/ex47/game.py

Make sense?

Unfortunately, I still don’t understand how modules relate to files.

Is the PYTHONPATH represented by . in this case the top-level ex47/ ? Or is it my home directory?

Running export PYTHONPATH="${PYTHONPATH}:/hard_way/projects/ex47"
in Terminal results in no errors on from ex47.game import Room, but it doesn’t run anything either. Nosetests are still fine.

When I move the game.py file into tests/, from tests.ex47.game import Room doesn’t find the module.

from .ex47.game import Room doesn’t work either.

Neither does renaming the file game_tests.py and moving it to tests/, then calling it by from ex47.game_tests import Room

The “.” means this directory. So export PYTHONPATH=. really means export pythonpath from here (wherever you run it from).

To be honest I recall having issues with Nose around this point and shifted to PyTest as I find it simple.

I remember I struggled with the same problem for some hours then I did ex47. I looked how I did it. I have the import in ex47_tests.py stated like this:

from ex47.game import Room

My directory structure:

|-- ex47_container
|    |--bin
|    |--docs
|    |--ex47
|    |    |--__init__.py
|    |    |--game.py
|    |--tests
|    |    |--__init__.py
|    |    |--ex47_tests.py
|    |--README.md
|    |--setup.py

It asumes that you are running your script from within the directory ex47_container like this:

$ pwd
> some_path/ex47_container
$ nosetests3 tests/ex47_tests.py 

So nosetests takes ex47_container as your “home” directory and then it calls the tests/ex47_tests.py file it sees that the ex47 directory (that with the __init__.py and the game.py files in it) is on the same level as tests so it can then grab the right file with the from ex47.game import Room command.

Imagine nosetests is a person and you are that person. You then have always a relative position to some fixed objects around you. Imagine you are in your apartment. The structure of your home is always the same (hopefully) but when you moving through your home the path to the different rooms always change. When you are in the kitchen you might to have to go to the left when you want to go to the living room but when you are in your bedroom you might to have to go to the right to reach your living room. When you call Python from a specific directory (or set your PYTHONPATH to a specific directory) you say Python where it is in the apartment. So you always have to give it the Path that is “relative” from the directory Python (or nose) is called. Normally that would be the home directory of your program, like ex47_container in my case.

I like to draw diagramms, so here it is one:
python_path

As you can see, your PATH to the moduls (everything with a __init__.py in it is recognised as a module) depends on the position you (or python or nose) is in. If you call ex47 from the corridor, the path is go to ex47 if you are in tests the path is first go to corridor then to ex47.
Hope that helps.

2 Likes

It’s so simple you’re just over thinking it. First we have to define two types of . (dots):

  1. PYTHONPATH=. <— this means “tell python to look for code in the current directory”. That’s all, and has nothing to do with the ex47.game dot.
  2. ex47.game <-- This acts as a separator for nested modules. I could have ex47.game.runner.thing.MyBadClass. It’s exactly the same as having an object and doing obj.attr, like in monster.kill().

The first PYTHONPATH=. is for your bash shell. Set that then forget about it.

The second . means get. It only ever means get. That is all it will ever mean ever. This is where everyone overcomplicates things, so get this burned in your brain:

ex47.game is the equivalent of ex47[‘game’], you are simply telling python “get ex47, AND THEN, get the attribute named ‘game’ from it.” Every dot does an AND THEN get. So if I have this:

ex47.game.player.Monster

It can be read as:

“Python, get ex47 AND THEN, get game from that, AND THEN, get player from that, AND THEN, get Monster from that.”

Ok, so how does that map to files? Every . maps to either a directory or a .py file.

ex47/  <-- ex47  . 
    game.py <-- game

You can think of the . as a / in a way. Now, what about that .player.Monster part I’m making up (that’s not really in your code)? That would be variables or objects inside your game.py file:

ex47/ <-- ex47 .
   game.py <-- game .
      player  <-- some variable in game.py
          Monster <-- some class in the player

But, I could also do those like this:

ex47/ 
    game/
         player.py
              class Monster

Now, your next move is to actually play with this rather than trying to read my description and figure it out intellectually. Experimentation is the way to go on this. Make some diretories, put .py files in there, put ```init.py`` files in there. Put code in the .py files. Try different ways to use . to get at the code in the files.

Remember . is kind of mapping to the / in a path:

ex47.game <----> ex47/game.py

I think I’m starting to understand. from ex47.game import Room throws no Tracebacks when run from the top-level ex47/ as python tests/ex47_tests.py It still doesn’t run any program, but at least there’s no errors. I’m guessing at this point my problem is not having a complete program capable of running anything, rather than a bad directory/module structure.

1 Like

Ok, if you can get your code into github.com then I can pull it and see what’s going on. Also, post a screenshot of your terminal at the point where you have an error.

Code here

As mentioned above, there is no error message when the nosetests pass. The program just doesn’t run:

Yes, it does work. Your tests ran. You see that line that states “Ran 3 tests in 0.004s”?

If you see something like that, when you know that everything works as expected. Try to change something in your tests so that it fails. And one of your tests should turn red.

But you can move forward now, everything is good :slight_smile:

1 Like

Ok, so I think I mentioned this before, but your tests need to be run in a special way. So when you do this:

python tests/ex47_tests.py

Why do you think it should “run”? Technically it did run. Python loaded it, setup all your functions, and since you didn’t tell python to do anything with those functions it quit. Look in the file. Where do you actually have code that calls those functions?

What nosetests does is it loads these test files, just like python, but it knows how to run the tests specially for you and print out messages and errors. So, your tests are running fine, and now you have to do some mental work:

You seem to have a misperception of what happens in a .py file when you define functions. You have to sit down and ask yourself, “Why did I think ex47_tests.py would run? What does run mean? Why didn’t it run?”

Reply back with your answers as I’m curious.

I understand now. The program did run, it just had nothing to display as no functions were called. This is why there were no error messages. I tried to include print statements, but those did not print anything, which I assume is because I did not call the function.

I thought ex47_tests.py would run as I did not understand that “testing” the code meant using nosetests, instead of running the program using a python command. This is why the nil result confused me.

I am assuming that nosetests catches failures that would not show up when running modules(?) using the python command on its own.

Yep, bingo! Now you get it. Basically, the code is just fine. You just have to use nosetests to run the test code. You should also take a look at pytest:

https://docs.pytest.org/en/latest/

It is a little easier to use and is actually maintained.

Hi Zed,
While on ex47, I ran into a problem with nosetests. Nosetests ran 3 tests on my ex47 and returned 3 fails all indicating the same TypeError: object() takes no parameters. The first error message is as follows:

self.test(*self.arg)

File “/Users/mchen/projects/ex47/ex47_tests.py”, line 8, in test_room
“”" This room has gold in it you can grab. There’s a door to the north.""")
TypeError: object() takes no parameters

Could you shed some light on where the problems are? Thanks.

I found out it is my own error to blame. The error message is caused by my mis-spelling of init in class Room and has nothing to do with nosetests. My bad.

2 Likes