0

First off I know this question has been asked 1000 times, but I cant seem to find an answer that works so sorry if this is a repeat, if you know a question that answers this please do share.

I've got the following directory structure:

my_app_dir
    ├── my_app
    │   ├── __init__.py
    │   ├── main.py
    │   ├── services
    │   │   ├── __init__.py
    │   │   └── my_service.py
    │   └── objects
    └── testing
        ├── service_tests
        │   ├── __init__.py
        │   └── test_my_service.py
        └── __init__.py

Im trying to import my_service from ./my_app_dir/my_app/services/my_service.py into my test case class test_my_service.py in ./my_app_dir/testing/service_tests/my_service.py

Im trying to import it in my module like so:

import unittest
from my_app.services.my_service import MyService

class MyTest(unittest.TestCase):
   ...


I get an error: cannot import module my_app...

the twist here is that im trying to run this in VS code with debugging. I have the following launch.json:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "cwd": "${workspaceFolder}"
        }
    ]
}

I did try adding to the PYTHONPATH in the launch.json like this:

"env":{
   "PYTHONPATH":"${PYTHONPATH}C:my_app_dir\\my_app"
} 

This test code needs to be portable to other machines so I would really like to not have to modify the sys path.

Is there an issue with how im importing the module and or the directory structure im using?

Thanks!

Ben Allen
  • 181
  • 1
  • 1
  • 9

2 Answers2

1

I am not sure why modifying sys.path would reduce portability:

# my_app_dir/testing/service_tests/my_service.py

import sys, os
initial_sys_path = sys.path.copy()

PATH_TO_MYAPPDIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
sys.path.append(PATH_TO_MYAPPDIR)

from my_app.services.my_service import MyService

# If you really want to clean sys.path afterwards
sys.path = initial_sys_path

However, there is also the possibility to use os.chdir as suggested in https://stackoverflow.com/a/61326547/6068769:

PATH_TO_MYAPPDIR = .... # same as above
os.chdir(PATH_TO_MYAPPDIR)
from my_app.services.my_service import MyService

Finally, I am not a VS user, but for the PYTHONPATH solution, I think the variable should point to C:\my_app_dir

"env":{
   "PYTHONPATH":"${PYTHONPATH}C:my_app_dir"
} 
Tawy
  • 579
  • 3
  • 14
  • Was trying to avoid the situation that I change the directory structure and have to modify my sys paths, but you are correct in saying that the way you have suggested is perfectly portable. The solution ended up being setting the env path correctly as you suggested. I'm still trying to wrap my head fully round how python handles imports. – Ben Allen Apr 22 '20 at 12:39
0

Simple question gets a simple answer. I was setting the PYTHONPATH incorrectly in the launch.json. I changed it to the following:

"env": {
                "PYTHONPATH": "${workspaceRoot}"
                }

Please correct me if this isn't the best way of doing this.

Ben Allen
  • 181
  • 1
  • 1
  • 9