chrisyeh96 / chrisyeh96.github.io

Personal website
https://chrisyeh96.github.io
MIT License
22 stars 22 forks source link

Definitive Python import guide #8

Closed kylepw closed 5 years ago

kylepw commented 5 years ago

Great guide! I enjoyed it and learned a lot. I have a question regarding relative imports. You mentioned that modules in parent directories couldn't be imported without messing with sys.path. I was wondering about unittest and if it's different? For example say I have a directory mod/ with module.py and a unit-test for that module, test_module.py, in mod/tests/, I should be able to import module in mod/tests/test_module.py and run python -m unittest tests/test_module.py even though it's importing from the parent directory, correct?

chrisyeh96 commented 5 years ago

Great question! Here is the short answer to your specific question:

  1. Assuming that your terminal's current path is at mod/, you can run python -m unittest tests/test_module.py.
  2. If your terminal's current path is anywhere else, you will see errors. For example, if your terminal's current path is at mod/tests/, then running python -m unittest test_module.py will fail.

Here's the longer explanation. The directory structure you described is as follows:

mod/
    module.py
    tests/
        test_module.py (contains "import module")

The usage of the -m flag for the Python interpreter is something I did not really address in my guide, because it introduces some of its own complications. Below is a quick primer.

Suppose that the terminal is currently at some directory dir/. Then, the following command starts a Python interpreter with sys.path[0] set to the empty string "" which refers to the current path /path/to/dir/.

/path/to/dir/> python -m <module_name>

Therefore, in case 1 described above (/path/to/mod/> python -m unittest tests/test_module.py), the mod/ directory is in sys.path, so test_module.py is able to successfully call import module.

However, in case 2 (/path/to/mod/tests/> python -m unittest test_module.py), mod/ is not in sys.path, so the call to import module fails.

kylepw commented 5 years ago

Thanks a lot @chrisyeh96 for the thorough response! Makes more sense now.