2

Why is that this code does not work (run with python3 x.py):

import os
os.chdir("/app/my-favorite-module")
from my_favorite_module.foo import Bar
os.chdir("/app")

(says no module called my_favorite_module`)

but using the Python REPL works (launched in the same directory as the script):

root@afad0fa67aa8:/content# python3
Python 3.10.6 (main, May 29 2023, 11:10:38) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os; os.chdir("/app/my-favorite-module")
>>> from my_favorite_module.foo import Bar
>>> os.chdir("/app")

I found a workaround using sys.path, but I'm curious about the underlying reason.

Foobar
  • 7,458
  • 16
  • 81
  • 161
  • Not sure `chdir` will shift the include path when run as a script. – tadman Jul 30 '23 at 22:26
  • maybe [this](https://stackoverflow.com/a/50279818/4935162) – Yarin_007 Jul 30 '23 at 22:27
  • It would be messy security-wise if `os.chdir` changed `sys.path` for scripts for the same reason that reasonable (non-Microsoft) people haven't added `.` to `PATH` for roughly four decades now. Inadvertently loading code from somewhere you didn't intentionally choose to trust is a Bad Thing. – Charles Duffy Jul 30 '23 at 22:50
  • The module search path is fixed when the script starts. I don't believe that calling `os.chdir()` has any effect. – John Gordon Jul 31 '23 at 01:25

1 Answers1

3

This is related to how the Python import system and module search paths work.

In the script version:

import os
os.chdir("/app/my-favorite-module")
from my_favorite_module.foo import Bar
os.chdir("/app")

When you change the current working directory using os.chdir, it only affects the script's current process and its child processes (if any). When the script is importing the module my_favorite_module.foo, Python searches for the module in the standard module search paths. Since you changed the working directory, the current directory is /app/my-favorite-module, and Python won't look in this directory for modules. Instead, it will look in the standard module paths, and thus, it will not find my_favorite_module.foo.

On the other hand, in the Python REPL version:

import os; os.chdir("/app/my-favorite-module")
from my_favorite_module.foo import Bar
os.chdir("/app")

The Python REPL runs interactively, and when you change the current working directory using os.chdir in the REPL, it affects the Python process running the REPL itself. As a result, when you then import my_favorite_module.foo, Python will search for the module in the current directory (/app/my-favorite-module), find it, and import it successfully.

As you've mentioned, using sys.path is a proper workaround for this situation. By adding the directory to sys.path, you are essentially telling Python to look in that directory when searching for modules, and this works consistently both in scripts and the Python REPL.

zoldxk
  • 2,632
  • 1
  • 7
  • 29