Ex48 import module clarification


#1

Hi everyone,

I have a doubt about import statements. I encountered the same problem during ex46 when trying to install my package using setup.py

I read several similar topics in the forum and in other forums but I’m still not sure about this.

So, this is my tree:

ex48/
    ex48/
        __init__.py
        lexicon.py
        pars.py
    tests/
        lexicon_tests.py
        pars_tests.py

The import statement in pars.py is:

from ex48.lexicon import scan

In pars_tests.py is:

from ex48 import pars

So far everything works fine. The tests run and we are happy.
But many times while I’m writing the code I want to run the pars.py script directly from the command line or the IDE to check what I just wrote.
But this will raise a ModuleNotFoundError unless I change the import statement in pars.py to:

from lexicon import scan

But of course this will then raise the error when I tried to run the tests.

Is there a way to keep both options available? (Run the tests successfully and also be able to run the scripts directly in the shell)

Thanks for your help!
:metal:


#2

That is probably because Python already has a parser module. If you try to require it with the name “parser” it’ll fail.


#3

I tried changing all the parser for pars but the issue persists.

I think I am not understanding completely the import statement rules, and I might not be explaining my doubt correctly.
The tree now looks like this:

The file pars.py imports the function scan from the module lexicon contained in the same folder.
In order for nosetests to work, the import looks like this:

from ex48.lexicon import scan

My question is if there is a way I can write the import statement so I would be able to do this:

ex48/ex48 $ python pars.py

and not get the error ModuleNotFoundError: No module named ‘ex48’

I hope this is more clear.
Thanks for the help.


#4

This is your problem:

ex48/ex48 $ python pars.py

And in fact, I go into a lot of yelling about this in the video. :wink:

You are telling python:

“Hey, go into the ex48 directory and load the file named lexicon.py”

Ok, but then you CD INTO EX48?

So you’re sitting inside ex48, then telling python to go into ex48, but you’re already in ex48.

Do this:

cd …

Never leave this place. You should be able to do:

ls -l

And see ex48 and tests directories right there. This is your home. Never go down below this. If you do nothing will work.

Try that. Than, let me know if you can explain why you went into ex48. It’s a constant problem and I really can’t figure out why people keep doing it.


#5

Oh, I think I got what you said about where to be to run the tests, you also mention it several times in the book :sweat_smile:

So, to run nosetests I always do it from above the ex48 and tests directories. And this works fine.

My problem appears when I want to run just the file pars.py (not its tests)
Since this file imports from another file, and the import statement is like we see above I completely understand that the program will not find another folder ex48 to go inside.

But when I change the import statement to

from lexicon import scan

Then, the nosetests won’t work.

I’m clearly missing something but I’ve tried many different ways and I still can’t figure out what’s wrong.


#6

Do me a favor:

cd ..

Ok, now you should be a the top above your ex48. To be sure that’s true THIS SHOULD FAIL:

cat ex48/lexicon.py

If that works then you ARE NOT IN THE RIGHT SPOT. cd …

So you should be able to do this:

ls ex48

And only see ex48 and tests.

Now, do this:

mv ex48 to myex48project

Now, cd into that directory:

cd myex48project.

Your directory should now be like this:

myex48project/
   ^------------------------------ you are here
      ex48/  <----- this is where python gets everything
          __init__.py
          lexicon.py
          pars.py
      tests/
          __init__.py
          lexicon_tests.py
          pars_tests.py

Ok, now change your code back to this:

from ex48.lexicon import scan

Then, explain to me what that’s doing, in steps, given that you have now named your project myex48project, so how does the above code work?


#7

Ok, first of all, thanks for taking your time doing this step by step course for me :sweat_smile:

I made the changes.
So, I am positioned inside myex48project/
The import statement of your last comment will make python:

  • First look inside ex48/
  • Then look inside the file lexicon.py
  • And then look for scan inside that file, which in this case is a function

With this configuration nosetests runs correctly.
My problem was when I tried to run from the same location

$ python ex48/pars.py

This would give me the error

ModuleNotFoundError: No module named 'ex48'

Which I makes sense, because there’s no module ex48 in the same location than the file pars.py
The program should go up one level for that import statement to make sense.

Then I tried again export PYTHONPATH=. and now it worked!
I had read other entries in the forum where you suggested this and you even mentioned it in the book, but my mistake was to always call that code in random places. Now I understand better that I have to call it while positioned in the folder that I want to add to the PYTHONPATH.

In this case I called it from myex48project/ and after that I was able to do

$ python ex48/pars.py

and the code ran correctly.

So, am I in the correct path?
Is this the way I should always structure my code and tree?
And should I always use PYTHONPATH to add the location and run my code from there (in this case _myex48project/)?

Thanks so so much!


#8

Yes, that is perfect. The PYTHONPATH=. then sets up the python ex48/pars.py to run it.