4

This question has been asked DOZENS of times before, but every one I've come across doesn't have any working solutions for me.

I'm using Python 2.7 and pytest to run tests.

Structure is as follows (from the root of my project/git repo):

myapp/
    myapp/
        __init__.py           # def main():
                              #    ... stuff
                              # if __name__ == "__main__":
                              #    main()

        __main__.py           # import __init__ as myapp
                              # myapp.main()

        config.yaml           # (app config file)

        myapplib/
                __init__.py   # (Empty file)

                config.py     # Loads {projectroot}/config.yaml
                              # def cfg(): 
                              #    ... stuff
    tests/
        test_stuff.py         # from myapplib.config import cfg

I then try to run the tests/test_stuff.py file by doing:

cd {projectroot}
pytest

And it complains:

myapp/tests/test_stuff.py:38: in <module>
    from myapplib.config import cfg
E   ImportError: No module named myapp.config

Some things I've tried:

  1. Using -m to import myapplib or myapp.myapplib
  2. Starting pytest from a different dir (e.g. inside tests/)
  3. Using all the path hacks in all the other answers
  4. Changing it to from . import XXX or .. or any of the relative import options (but these all fail with ValueError: Attempted relative import in non-package.

Worth nothing that the app itself executes fine from the project dir:

cd {projectroot}
python myapp

... and all config and paths work just fine. It's just the tests that can't find the path.


Here's a complete reproduction of what I have so far:

https://pyfiddle.io/fiddle/4fa60f5a-02df-43bb-8aa3-03e59ff72650/?m=Saved%20fiddle

brandonscript
  • 68,675
  • 32
  • 163
  • 220

1 Answers1

2

you're running

myapp/tests/test_stuff.py

you need to edit the path in test_stuff.py to point to myapp (which contains __init__.py)

I tested this on my system (file test_stuff.py):

import sys,os
sys.path.append(os.path.join(os.path.dirname(__file__),os.pardir,"myapp"))
import myapplib

(getting full path of your python module, then using parent dir to add the python path to just the second level of myapp)

works on my dirtree configured like yours:

S:\python\myapp\myapp
S:\python\myapp\tests
S:\python\myapp\myapp\myapplib
S:\python\myapp\myapp\myapplib\__init__.py
S:\python\myapp\tests\test_stuff.py

Advice: when fiddling with sys.path.append():

  • always use absolute paths, using __file__ to make sure that the current directory doesn't get in the way. never depend on the current directory, or this trick will only work when in a given directory.
  • debug: print the path you're adding to check if it's the proper one. Since it's absolute, you'll easily see if it's correct.
brandonscript
  • 68,675
  • 32
  • 163
  • 220
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • Alright, I must be doing something wrong. I added the path.append() to `/myapp/__init__.py`, and still no dice. I created a brand new project just to be safe, and still nothing. For what it's worth, from that path string I'm getting `myapp/../myapp`. – brandonscript Feb 08 '18 at 23:38
  • Here's a fiddle with a complete reproduction of my test project with your changes: https://pyfiddle.io/fiddle/4fa60f5a-02df-43bb-8aa3-03e59ff72650/?m=Saved%20fiddle – brandonscript Feb 08 '18 at 23:50
  • @brandonscript seems that there's a confusion here. The snippet I mentionned must be in `test_stuff.py`. you put my code in myapp init instead... BTW fiddle doesn't care about your triple quote filenames. It just ignores them, uses "main.py". – Jean-François Fabre Feb 09 '18 at 21:03
  • Ohhh I see, your answer made it should like I was supposed to put it in __init__.py. That doesn’t make much sense, does it ;). And yes- the fiddle was just me trying to keep it all in one place rather than separate files. – brandonscript Feb 09 '18 at 21:13
  • altering the `sys.path` only works for the one which imports the module. I have edited my post to clear the confusion – Jean-François Fabre Feb 09 '18 at 21:15
  • Yeah, that makes way more sense. Want to edit the q to make that more clear? I’ll accept - it works now. – brandonscript Feb 09 '18 at 21:17
  • I don't think it's necessary. your question error is `myapp/tests/test_stuff.py:38: in from myapplib.config import cfg`. Glad that it worked, cos I put some effort reproducing your file tree :) – Jean-François Fabre Feb 09 '18 at 21:18
  • I edited the part that confused me. Let me know if that’s ok! – brandonscript Feb 09 '18 at 21:21